From 0f5e22c248b7b9bc26d95434ae05d21cc73d19b8 Mon Sep 17 00:00:00 2001 From: iamayushm <32041961+iamayushm@users.noreply.github.com> Date: Thu, 28 Dec 2023 16:00:43 +0530 Subject: [PATCH] feat: manual sync for argocd apps (#4392) * argocd manual sync code * removing unused function * changing sync timeline time * sync time update * creating constant for application template * updating sync time in cron * adding argocd sync timeline in helm apps * fixing wire issue * making autosync mode dynamic in application template * dev testing changes * adding manual sync support for rollback and chart group * fix make error * fixing cron * fix: helm app sync condition in cron * fixing error handling in rollback * wip: returning err * adding context in rollback funtion * wip * fix githash update * wip * removing argocd_sync_initiated timeline * updating sync time * pr review changes * fix wire * adding check for argo manual sync disabled --- Dockerfile | 2 +- .../deployment/CommonDeploymentRestHandler.go | 27 ++- .../deployment/wire_appStoreDeployment.go | 2 + .../argocdServer/ArgoClientWrapperService.go | 93 +++++++++ client/argocdServer/k8sClient.go | 12 +- .../cron/CdApplicationStatusUpdateHandler.go | 6 +- cmd/external-app/wire_gen.go | 9 +- .../PipelineStatusTimelineRepository.go | 13 +- pkg/app/AppService.go | 79 +++---- pkg/app/ManifestPushService.go | 73 ++++--- .../status/PipelineStatusTimelineService.go | 83 +++++++- .../AppStoreDeploymentFullModeService.go | 82 +++----- .../repository/InstalledAppVersionHistory.go | 11 +- .../service/AppStoreDeploymentService.go | 83 ++++---- .../deployment/service/InstalledAppService.go | 46 ++++- .../tool/AppStoreDeploymentHelmService.go | 6 +- .../gitops/AppStoreDeploymentArgoCdService.go | 121 ++++++++--- pkg/pipeline/CdHandler.go | 194 +++++++++++++++++- pkg/pipeline/WorkflowDagExecutor.go | 88 +++++--- ...EMPLATE.JSON => APPLICATION_TEMPLATE.tmpl} | 6 +- wire_gen.go | 24 ++- 21 files changed, 757 insertions(+), 303 deletions(-) rename scripts/argo-assets/{APPLICATION_TEMPLATE.JSON => APPLICATION_TEMPLATE.tmpl} (92%) diff --git a/Dockerfile b/Dockerfile index 9c107dcf84..79108d052d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ COPY --from=build-env /go/src/github.com/devtron-labs/devtron/vendor/github.com COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/devtron-reference-helm-charts scripts/devtron-reference-helm-charts COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/sql scripts/sql COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/casbin scripts/casbin -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/argo-assets/APPLICATION_TEMPLATE.JSON scripts/argo-assets/APPLICATION_TEMPLATE.JSON +COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/argo-assets/APPLICATION_TEMPLATE.tmpl scripts/argo-assets/APPLICATION_TEMPLATE.tmpl COPY ./git-ask-pass.sh /git-ask-pass.sh RUN chmod +x /git-ask-pass.sh diff --git a/api/appStore/deployment/CommonDeploymentRestHandler.go b/api/appStore/deployment/CommonDeploymentRestHandler.go index 937873e6fb..3007044262 100644 --- a/api/appStore/deployment/CommonDeploymentRestHandler.go +++ b/api/appStore/deployment/CommonDeploymentRestHandler.go @@ -32,6 +32,7 @@ import ( "github.com/devtron-labs/devtron/pkg/user" "github.com/devtron-labs/devtron/pkg/user/casbin" util2 "github.com/devtron-labs/devtron/util" + "github.com/devtron-labs/devtron/util/argo" "github.com/devtron-labs/devtron/util/rbac" "github.com/gorilla/mux" "go.opentelemetry.io/otel" @@ -59,12 +60,13 @@ type CommonDeploymentRestHandlerImpl struct { validator *validator.Validate helmAppService client.HelmAppService helmAppRestHandler client.HelmAppRestHandler + argoUserService argo.ArgoUserService } func NewCommonDeploymentRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService user.UserService, enforcer casbin.Enforcer, enforcerUtil rbac.EnforcerUtil, enforcerUtilHelm rbac.EnforcerUtilHelm, appStoreDeploymentService service.AppStoreDeploymentService, validator *validator.Validate, helmAppService client.HelmAppService, appStoreDeploymentServiceC appStoreDeploymentCommon.AppStoreDeploymentCommonService, - helmAppRestHandler client.HelmAppRestHandler) *CommonDeploymentRestHandlerImpl { + helmAppRestHandler client.HelmAppRestHandler, argoUserService argo.ArgoUserService) *CommonDeploymentRestHandlerImpl { return &CommonDeploymentRestHandlerImpl{ Logger: Logger, userAuthService: userAuthService, @@ -76,6 +78,7 @@ func NewCommonDeploymentRestHandlerImpl(Logger *zap.SugaredLogger, userAuthServi helmAppService: helmAppService, appStoreDeploymentServiceC: appStoreDeploymentServiceC, helmAppRestHandler: helmAppRestHandler, + argoUserService: argoUserService, } } func (handler *CommonDeploymentRestHandlerImpl) getAppOfferingMode(installedAppId string, appId string) (string, *appStoreBean.InstallAppVersionDTO, error) { @@ -287,8 +290,28 @@ func (handler *CommonDeploymentRestHandlerImpl) RollbackApplication(w http.Respo return } //rbac block ends here + ctx, cancel := context.WithCancel(r.Context()) + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + if util2.IsBaseStack() || util2.IsHelmApp(appOfferingMode) { + ctx = context.WithValue(r.Context(), "token", token) + } else { + acdToken, err := handler.argoUserService.GetLatestDevtronArgoCdUserToken() + if err != nil { + handler.Logger.Errorw("error in getting acd token", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + ctx = context.WithValue(r.Context(), "token", acdToken) + } - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() success, err := handler.appStoreDeploymentService.RollbackApplication(ctx, request, installedAppDto, userId) if err != nil { diff --git a/api/appStore/deployment/wire_appStoreDeployment.go b/api/appStore/deployment/wire_appStoreDeployment.go index 10178a9f5c..da9d39a798 100644 --- a/api/appStore/deployment/wire_appStoreDeployment.go +++ b/api/appStore/deployment/wire_appStoreDeployment.go @@ -1,6 +1,7 @@ package appStoreDeployment import ( + "github.com/devtron-labs/devtron/client/argocdServer" appStoreDeploymentCommon "github.com/devtron-labs/devtron/pkg/appStore/deployment/common" "github.com/devtron-labs/devtron/pkg/appStore/deployment/repository" "github.com/devtron-labs/devtron/pkg/appStore/deployment/service" @@ -29,4 +30,5 @@ var AppStoreDeploymentWireSet = wire.NewSet( wire.Bind(new(CommonDeploymentRestHandler), new(*CommonDeploymentRestHandlerImpl)), NewCommonDeploymentRouterImpl, wire.Bind(new(CommonDeploymentRouter), new(*CommonDeploymentRouterImpl)), + argocdServer.GetACDDeploymentConfig, ) diff --git a/client/argocdServer/ArgoClientWrapperService.go b/client/argocdServer/ArgoClientWrapperService.go index 93682ee20a..3cd2cf7380 100644 --- a/client/argocdServer/ArgoClientWrapperService.go +++ b/client/argocdServer/ArgoClientWrapperService.go @@ -3,26 +3,53 @@ package argocdServer import ( "context" application2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/caarlos0/env" "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/client/argocdServer/bean" "go.uber.org/zap" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +type ACDConfig struct { + ArgoCDAutoSyncEnabled bool `env:"ARGO_AUTO_SYNC_ENABLED" envDefault:"true"` //will gradually switch this flag to false in enterprise +} + +func GetACDDeploymentConfig() (*ACDConfig, error) { + cfg := &ACDConfig{} + err := env.Parse(cfg) + if err != nil { + return nil, err + } + return cfg, err +} + type ArgoClientWrapperService interface { + + //GetArgoAppWithNormalRefresh - refresh app at argocd side GetArgoAppWithNormalRefresh(context context.Context, argoAppName string) error + + //SyncArgoCDApplicationIfNeededAndRefresh - if ARGO_AUTO_SYNC_ENABLED=true, app will be refreshed to initiate refresh at argoCD side or else it will be synced and refreshed + SyncArgoCDApplicationIfNeededAndRefresh(context context.Context, argoAppName string) error + + // UpdateArgoCDSyncModeIfNeeded - if ARGO_AUTO_SYNC_ENABLED=true and app is in manual sync mode or vice versa update app + UpdateArgoCDSyncModeIfNeeded(ctx context.Context, argoApplication *v1alpha1.Application) (err error) } type ArgoClientWrapperServiceImpl struct { logger *zap.SugaredLogger acdClient application.ServiceClient + ACDConfig *ACDConfig } func NewArgoClientWrapperServiceImpl(logger *zap.SugaredLogger, acdClient application.ServiceClient, + ACDConfig *ACDConfig, ) *ArgoClientWrapperServiceImpl { return &ArgoClientWrapperServiceImpl{ logger: logger, acdClient: acdClient, + ACDConfig: ACDConfig, } } @@ -37,3 +64,69 @@ func (impl *ArgoClientWrapperServiceImpl) GetArgoAppWithNormalRefresh(context co impl.logger.Debugw("done getting the application with refresh with no error", "argoAppName", argoAppName) return nil } + +func (impl *ArgoClientWrapperServiceImpl) SyncArgoCDApplicationIfNeededAndRefresh(context context.Context, argoAppName string) error { + impl.logger.Info("argocd manual sync for app started", "argoAppName", argoAppName) + if !impl.ACDConfig.ArgoCDAutoSyncEnabled { + impl.logger.Debugw("syncing argocd app as manual sync is enabled", "argoAppName", argoAppName) + revision := "master" + pruneResources := true + _, syncErr := impl.acdClient.Sync(context, &application2.ApplicationSyncRequest{Name: &argoAppName, Revision: &revision, Prune: &pruneResources}) + if syncErr != nil { + impl.logger.Errorw("cannot get application with refresh", "app", argoAppName) + return syncErr + } + impl.logger.Debugw("argocd sync completed", "argoAppName", argoAppName) + } + refreshErr := impl.GetArgoAppWithNormalRefresh(context, argoAppName) + if refreshErr != nil { + impl.logger.Errorw("error in refreshing argo app", "err", refreshErr) + } + return nil +} + +func (impl *ArgoClientWrapperServiceImpl) UpdateArgoCDSyncModeIfNeeded(ctx context.Context, argoApplication *v1alpha1.Application) (err error) { + if impl.isArgoAppSyncModeMigrationNeeded(argoApplication) { + syncModeUpdateRequest := impl.CreateRequestForArgoCDSyncModeUpdateRequest(argoApplication) + validate := false + _, err = impl.acdClient.Update(ctx, &application2.ApplicationUpdateRequest{Application: syncModeUpdateRequest, Validate: &validate}) + if err != nil { + impl.logger.Errorw("error in creating argo pipeline ", "name", argoApplication.Name, "err", err) + return err + } + } + return nil +} + +func (impl *ArgoClientWrapperServiceImpl) isArgoAppSyncModeMigrationNeeded(argoApplication *v1alpha1.Application) bool { + if !impl.ACDConfig.ArgoCDAutoSyncEnabled && argoApplication.Spec.SyncPolicy.Automated != nil { + return true + } + if impl.ACDConfig.ArgoCDAutoSyncEnabled && argoApplication.Spec.SyncPolicy.Automated == nil { + return true + } + return false +} + +func (impl *ArgoClientWrapperServiceImpl) CreateRequestForArgoCDSyncModeUpdateRequest(argoApplication *v1alpha1.Application) *v1alpha1.Application { + // set automated field in update request + var automated *v1alpha1.SyncPolicyAutomated + if impl.ACDConfig.ArgoCDAutoSyncEnabled { + automated = &v1alpha1.SyncPolicyAutomated{ + Prune: true, + } + } + return &v1alpha1.Application{ + ObjectMeta: v1.ObjectMeta{ + Name: argoApplication.Name, + Namespace: DevtronInstalationNs, + }, + Spec: v1alpha1.ApplicationSpec{ + Destination: argoApplication.Spec.Destination, + Source: argoApplication.Spec.Source, + SyncPolicy: &v1alpha1.SyncPolicy{ + Automated: automated, + SyncOptions: argoApplication.Spec.SyncPolicy.SyncOptions, + Retry: argoApplication.Spec.SyncPolicy.Retry, + }}} +} diff --git a/client/argocdServer/k8sClient.go b/client/argocdServer/k8sClient.go index 3f1106521c..a1bd115356 100644 --- a/client/argocdServer/k8sClient.go +++ b/client/argocdServer/k8sClient.go @@ -26,12 +26,16 @@ type AppTemplate struct { ValuesFile string RepoPath string RepoUrl string + AutoSyncEnabled bool } -const TimeoutSlow = 30 * time.Second +const ( + TimeoutSlow = 30 * time.Second + ARGOCD_APPLICATION_TEMPLATE = "./scripts/argo-assets/APPLICATION_TEMPLATE.tmpl" +) type ArgoK8sClient interface { - CreateAcdApp(appRequest *AppTemplate, cluster *repository.Cluster) (string, error) + CreateAcdApp(appRequest *AppTemplate, cluster *repository.Cluster, applicationTemplatePath string) (string, error) GetArgoApplication(namespace string, appName string, cluster *repository.Cluster) (map[string]interface{}, error) } type ArgoK8sClientImpl struct { @@ -58,8 +62,8 @@ func (impl ArgoK8sClientImpl) tprintf(tmpl string, data interface{}) (string, er return buf.String(), nil } -func (impl ArgoK8sClientImpl) CreateAcdApp(appRequest *AppTemplate, cluster *repository.Cluster) (string, error) { - chartYamlContent, err := ioutil.ReadFile(filepath.Clean("./scripts/argo-assets/APPLICATION_TEMPLATE.JSON")) +func (impl ArgoK8sClientImpl) CreateAcdApp(appRequest *AppTemplate, cluster *repository.Cluster, applicationTemplatePath string) (string, error) { + chartYamlContent, err := ioutil.ReadFile(filepath.Clean(applicationTemplatePath)) if err != nil { impl.logger.Errorw("err in reading template", "err", err) return "", err diff --git a/client/cron/CdApplicationStatusUpdateHandler.go b/client/cron/CdApplicationStatusUpdateHandler.go index 140729b1f0..42550080eb 100644 --- a/client/cron/CdApplicationStatusUpdateHandler.go +++ b/client/cron/CdApplicationStatusUpdateHandler.go @@ -131,7 +131,7 @@ func (impl *CdApplicationStatusUpdateHandlerImpl) Subscribe() error { impl.logger.Debugw("ARGO_PIPELINE_STATUS_UPDATE_REQ", "stage", "subscribeDataUnmarshal", "data", statusUpdateEvent) if statusUpdateEvent.IsAppStoreApplication { - installedApp, err = impl.installedAppVersionRepository.GetInstalledAppByInstalledAppVersionId(statusUpdateEvent.PipelineId) + installedApp, err = impl.installedAppVersionRepository.GetInstalledAppByInstalledAppVersionId(statusUpdateEvent.InstalledAppVersionId) if err != nil { impl.logger.Errorw("error in getting installedAppVersion by id", "err", err, "id", statusUpdateEvent.PipelineId) return @@ -221,7 +221,7 @@ func (impl *CdApplicationStatusUpdateHandlerImpl) SyncPipelineStatusForResourceT return nil } if !util.IsTerminalStatus(cdWfr.Status) { - impl.CdHandler.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipeline.Id, 1, false) + impl.CdHandler.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipeline.Id, 0, 1, false) } return nil } @@ -234,7 +234,7 @@ func (impl *CdApplicationStatusUpdateHandlerImpl) SyncPipelineStatusForAppStoreF return nil } if !util.IsTerminalStatus(installedAppVersionHistory.Status) { - impl.CdHandler.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(installedAppVersion.Id, 1, true) + impl.CdHandler.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(0, installedAppVersion.Id, 1, true) } return nil } diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index 6fde0ae593..85b56232a5 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -33,6 +33,7 @@ import ( terminal2 "github.com/devtron-labs/devtron/api/terminal" user2 "github.com/devtron-labs/devtron/api/user" webhookHelm2 "github.com/devtron-labs/devtron/api/webhook/helm" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/client/dashboard" "github.com/devtron-labs/devtron/client/telemetry" repository3 "github.com/devtron-labs/devtron/internal/sql/repository" @@ -281,7 +282,11 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - appStoreDeploymentServiceImpl := service3.NewAppStoreDeploymentServiceImpl(sugaredLogger, installedAppRepositoryImpl, chartGroupDeploymentRepositoryImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, clusterInstalledAppsRepositoryImpl, appRepositoryImpl, appStoreDeploymentHelmServiceImpl, appStoreDeploymentHelmServiceImpl, environmentServiceImpl, clusterServiceImpl, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, globalEnvVariables, installedAppVersionHistoryRepositoryImpl, gitOpsConfigRepositoryImpl, attributesServiceImpl, deploymentServiceTypeConfig, chartTemplateServiceImpl) + acdConfig, err := argocdServer.GetACDDeploymentConfig() + if err != nil { + return nil, err + } + appStoreDeploymentServiceImpl := service3.NewAppStoreDeploymentServiceImpl(sugaredLogger, installedAppRepositoryImpl, chartGroupDeploymentRepositoryImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, clusterInstalledAppsRepositoryImpl, appRepositoryImpl, appStoreDeploymentHelmServiceImpl, appStoreDeploymentHelmServiceImpl, environmentServiceImpl, clusterServiceImpl, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, globalEnvVariables, installedAppVersionHistoryRepositoryImpl, gitOpsConfigRepositoryImpl, attributesServiceImpl, deploymentServiceTypeConfig, chartTemplateServiceImpl, acdConfig) appStoreDeploymentRestHandlerImpl := appStoreDeployment.NewAppStoreDeploymentRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, appStoreDeploymentServiceImpl, validate, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, helmUserServiceImpl, attributesServiceImpl) appStoreDeploymentRouterImpl := appStoreDeployment.NewAppStoreDeploymentRouterImpl(appStoreDeploymentRestHandlerImpl) chartProviderServiceImpl := chartProvider.NewChartProviderServiceImpl(sugaredLogger, chartRepoRepositoryImpl, chartRepositoryServiceImpl, dockerArtifactStoreRepositoryImpl, ociRegistryConfigRepositoryImpl) @@ -300,7 +305,7 @@ func InitializeApp() (*App, error) { } dashboardTelemetryRestHandlerImpl := dashboardEvent.NewDashboardTelemetryRestHandlerImpl(sugaredLogger, telemetryEventClientImpl) dashboardTelemetryRouterImpl := dashboardEvent.NewDashboardTelemetryRouterImpl(dashboardTelemetryRestHandlerImpl) - commonDeploymentRestHandlerImpl := appStoreDeployment.NewCommonDeploymentRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, appStoreDeploymentServiceImpl, validate, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, helmAppRestHandlerImpl) + commonDeploymentRestHandlerImpl := appStoreDeployment.NewCommonDeploymentRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, appStoreDeploymentServiceImpl, validate, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, helmAppRestHandlerImpl, helmUserServiceImpl) commonDeploymentRouterImpl := appStoreDeployment.NewCommonDeploymentRouterImpl(commonDeploymentRestHandlerImpl) externalLinkMonitoringToolRepositoryImpl := externalLink.NewExternalLinkMonitoringToolRepositoryImpl(db) externalLinkIdentifierMappingRepositoryImpl := externalLink.NewExternalLinkIdentifierMappingRepositoryImpl(db) diff --git a/internal/sql/repository/pipelineConfig/PipelineStatusTimelineRepository.go b/internal/sql/repository/pipelineConfig/PipelineStatusTimelineRepository.go index e75994979e..ecc28ac5e6 100644 --- a/internal/sql/repository/pipelineConfig/PipelineStatusTimelineRepository.go +++ b/internal/sql/repository/pipelineConfig/PipelineStatusTimelineRepository.go @@ -15,6 +15,8 @@ const ( TIMELINE_STATUS_DEPLOYMENT_INITIATED TimelineStatus = "DEPLOYMENT_INITIATED" TIMELINE_STATUS_GIT_COMMIT TimelineStatus = "GIT_COMMIT" TIMELINE_STATUS_GIT_COMMIT_FAILED TimelineStatus = "GIT_COMMIT_FAILED" + TIMELINE_STATUS_ARGOCD_SYNC_INITIATED TimelineStatus = "ARGOCD_SYNC_INITIATED" + TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED TimelineStatus = "ARGOCD_SYNC_COMPLETED" TIMELINE_STATUS_KUBECTL_APPLY_STARTED TimelineStatus = "KUBECTL_APPLY_STARTED" TIMELINE_STATUS_KUBECTL_APPLY_SYNCED TimelineStatus = "KUBECTL_APPLY_SYNCED" TIMELINE_STATUS_APP_HEALTHY TimelineStatus = "HEALTHY" @@ -50,6 +52,7 @@ type PipelineStatusTimelineRepository interface { DeleteByCdWfrIdAndTimelineStatusesWithTxn(cdWfrId int, status []TimelineStatus, tx *pg.Tx) error FetchTimelinesByInstalledAppVersionHistoryId(installedAppVersionHistoryId int) ([]*PipelineStatusTimeline, error) FetchLatestTimelinesByInstalledAppVersionHistoryId(installedAppVersionHistoryId int) (*PipelineStatusTimeline, error) + GetConnection() *pg.DB } type PipelineStatusTimelineRepositoryImpl struct { @@ -125,9 +128,10 @@ func (impl *PipelineStatusTimelineRepositoryImpl) FetchTimelinesByPipelineId(pip } func (impl *PipelineStatusTimelineRepositoryImpl) FetchTimelinesByWfrId(wfrId int) ([]*PipelineStatusTimeline, error) { + //ignoring 'ARGOCD_SYNC_INITIATED' in sql query as it is not handled at FE var timelines []*PipelineStatusTimeline err := impl.dbConnection.Model(&timelines). - Where("cd_workflow_runner_id = ?", wfrId). + Where("cd_workflow_runner_id = ? and status !='ARGOCD_SYNC_INITIATED' ", wfrId). Order("status_time ASC").Select() if err != nil { impl.logger.Errorw("error in getting timelines by wfrId", "err", err, "wfrId", wfrId) @@ -270,9 +274,10 @@ func (impl *PipelineStatusTimelineRepositoryImpl) DeleteByCdWfrIdAndTimelineStat } func (impl *PipelineStatusTimelineRepositoryImpl) FetchTimelinesByInstalledAppVersionHistoryId(installedAppVersionHistoryId int) ([]*PipelineStatusTimeline, error) { + //ignoring 'ARGOCD_SYNC_INITIATED' in sql query as it is not handled at FE var timelines []*PipelineStatusTimeline err := impl.dbConnection.Model(&timelines). - Where("installed_app_version_history_id = ?", installedAppVersionHistoryId). + Where("installed_app_version_history_id = ? and status !='ARGOCD_SYNC_INITIATED'", installedAppVersionHistoryId). Order("status_time ASC").Select() if err != nil { impl.logger.Errorw("error in getting timelines by installAppVersionHistoryId", "err", err, "wfrId", installedAppVersionHistoryId) @@ -293,3 +298,7 @@ func (impl *PipelineStatusTimelineRepositoryImpl) FetchLatestTimelinesByInstalle } return timeline, nil } + +func (impl *PipelineStatusTimelineRepositoryImpl) GetConnection() *pg.DB { + return impl.dbConnection +} diff --git a/pkg/app/AppService.go b/pkg/app/AppService.go index 60e73d4485..838a5ee37d 100644 --- a/pkg/app/AppService.go +++ b/pkg/app/AppService.go @@ -80,15 +80,16 @@ import ( ) type AppServiceConfig struct { - CdPipelineStatusCronTime string `env:"CD_PIPELINE_STATUS_CRON_TIME" envDefault:"*/2 * * * *"` - CdHelmPipelineStatusCronTime string `env:"CD_HELM_PIPELINE_STATUS_CRON_TIME" envDefault:"*/2 * * * *"` - CdPipelineStatusTimeoutDuration string `env:"CD_PIPELINE_STATUS_TIMEOUT_DURATION" envDefault:"20"` //in minutes - PipelineDegradedTime string `env:"PIPELINE_DEGRADED_TIME" envDefault:"10"` //in minutes - GetPipelineDeployedWithinHours int `env:"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS" envDefault:"12"` //in hours - HelmPipelineStatusCheckEligibleTime string `env:"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME" envDefault:"120"` //in seconds - ExposeCDMetrics bool `env:"EXPOSE_CD_METRICS" envDefault:"false"` - EnableAsyncInstallDevtronChart bool `env:"ENABLE_ASYNC_INSTALL_DEVTRON_CHART" envDefault:"false"` - DevtronChartInstallRequestTimeout int `env:"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT" envDefault:"6"` //in minutes + CdPipelineStatusCronTime string `env:"CD_PIPELINE_STATUS_CRON_TIME" envDefault:"*/2 * * * *"` + CdHelmPipelineStatusCronTime string `env:"CD_HELM_PIPELINE_STATUS_CRON_TIME" envDefault:"*/2 * * * *"` + CdPipelineStatusTimeoutDuration string `env:"CD_PIPELINE_STATUS_TIMEOUT_DURATION" envDefault:"20"` //in minutes + PipelineDegradedTime string `env:"PIPELINE_DEGRADED_TIME" envDefault:"10"` //in minutes + GetPipelineDeployedWithinHours int `env:"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS" envDefault:"12"` //in hours + HelmPipelineStatusCheckEligibleTime string `env:"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME" envDefault:"120"` //in seconds + ExposeCDMetrics bool `env:"EXPOSE_CD_METRICS" envDefault:"false"` + EnableAsyncInstallDevtronChart bool `env:"ENABLE_ASYNC_INSTALL_DEVTRON_CHART" envDefault:"false"` + DevtronChartInstallRequestTimeout int `env:"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT" envDefault:"6"` + ArgocdManualSyncCronPipelineDeployedBefore int `env:"ARGO_APP_MANUAL_SYNC_TIME" envDefault:"3"` //in minutes } func GetAppServiceConfig() (*AppServiceConfig, error) { @@ -164,6 +165,7 @@ type AppServiceImpl struct { GitOpsManifestPushService GitOpsPushService scopedVariableManager variables.ScopedVariableCMCSManager argoClientWrapperService argocdServer.ArgoClientWrapperService + acdConfig *argocdServer.ACDConfig } type AppService interface { @@ -248,6 +250,7 @@ func NewAppService( GitOpsManifestPushService GitOpsPushService, argoClientWrapperService argocdServer.ArgoClientWrapperService, scopedVariableManager variables.ScopedVariableCMCSManager, + acdConfig *argocdServer.ACDConfig, ) *AppServiceImpl { appServiceImpl := &AppServiceImpl{ environmentConfigRepository: environmentConfigRepository, @@ -311,6 +314,7 @@ func NewAppService( GitOpsManifestPushService: GitOpsManifestPushService, argoClientWrapperService: argoClientWrapperService, scopedVariableManager: scopedVariableManager, + acdConfig: acdConfig, } return appServiceImpl } @@ -352,7 +356,6 @@ func (impl *AppServiceImpl) UpdateDeploymentStatusAndCheckIsSucceeded(app *v1alp impl.logger.Errorw("error occurred while updating app status in app_status table", "error", err, "appId", installAppDeleteRequest.AppId, "envId", installAppDeleteRequest.EnvironmentId) } impl.logger.Debugw("skipping application status update as this app is chart", "appId", installAppDeleteRequest.AppId, "envId", installAppDeleteRequest.EnvironmentId) - return isSucceeded, pipelineOverride, nil } } else { repoUrl := app.Spec.Source.RepoURL @@ -377,7 +380,6 @@ func (impl *AppServiceImpl) UpdateDeploymentStatusAndCheckIsSucceeded(app *v1alp impl.logger.Errorw("error occurred while updating app status in app_status table", "error", err, "appId", chart.AppId, "envId", envId) } impl.logger.Debugw("skipping application status update as this app is chart", "appId", chart.AppId, "envId", envId) - return isSucceeded, pipelineOverride, nil } } @@ -582,6 +584,12 @@ func (impl *AppServiceImpl) CheckIfPipelineUpdateEventIsValidForAppStore(gitOpsA //drop event return isValid, installedAppVersionHistory, appId, envId, nil } + if !impl.acdConfig.ArgoCDAutoSyncEnabled { + isArgoAppSynced := impl.pipelineStatusTimelineService.GetArgoAppSyncStatusForAppStore(installedAppVersionHistory.Id) + if !isArgoAppSynced { + return isValid, installedAppVersionHistory, appId, envId, nil + } + } isValid = true return isValid, installedAppVersionHistory, appId, envId, err } @@ -625,6 +633,13 @@ func (impl *AppServiceImpl) CheckIfPipelineUpdateEventIsValid(argoAppName, gitHa //drop event return isValid, pipeline, cdWfr, pipelineOverride, nil } + if !impl.acdConfig.ArgoCDAutoSyncEnabled { + // if manual sync, proceed only if ARGOCD_SYNC_COMPLETED timeline is created + isArgoAppSynced := impl.pipelineStatusTimelineService.GetArgoAppSyncStatus(cdWfr.Id) + if !isArgoAppSynced { + return isValid, pipeline, cdWfr, pipelineOverride, nil + } + } isValid = true return isValid, pipeline, cdWfr, pipelineOverride, nil } @@ -696,7 +711,7 @@ func (impl *AppServiceImpl) UpdatePipelineStatusTimelineForApplicationChanges(ap timeline.StatusDetail = app.Status.OperationState.Message } //checking and saving if this timeline is present or not because kubewatch may stream same objects multiple times - _, err, isTimelineUpdated = impl.SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId, timeline.Status, timeline, false) + _, err, isTimelineUpdated = impl.pipelineStatusTimelineService.SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId, timeline.Status, timeline, false) if err != nil { impl.logger.Errorw("error in saving pipeline status timeline", "err", err) return isTimelineUpdated, isTimelineTimedOut, kubectlApplySyncedTimeline, err @@ -759,7 +774,7 @@ func (impl *AppServiceImpl) UpdatePipelineStatusTimelineForApplicationChanges(ap //mark as timed out if not already marked timeline.Status = pipelineConfig.TIMELINE_STATUS_FETCH_TIMED_OUT timeline.StatusDetail = "Deployment timed out." - _, err, isTimelineUpdated = impl.SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId, timeline.Status, timeline, false) + _, err, isTimelineUpdated = impl.pipelineStatusTimelineService.SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId, timeline.Status, timeline, false) if err != nil { impl.logger.Errorw("error in saving pipeline status timeline", "err", err) return isTimelineUpdated, isTimelineTimedOut, kubectlApplySyncedTimeline, err @@ -799,7 +814,7 @@ func (impl *AppServiceImpl) UpdatePipelineStatusTimelineForApplicationChanges(ap timeline.StatusDetail = app.Status.OperationState.Message } //checking and saving if this timeline is present or not because kubewatch may stream same objects multiple times - _, err, isTimelineUpdated = impl.SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId, timeline.Status, timeline, true) + _, err, isTimelineUpdated = impl.pipelineStatusTimelineService.SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId, timeline.Status, timeline, true) if err != nil { impl.logger.Errorw("error in saving pipeline status timeline", "err", err) return isTimelineUpdated, isTimelineTimedOut, kubectlApplySyncedTimeline, err @@ -862,7 +877,7 @@ func (impl *AppServiceImpl) UpdatePipelineStatusTimelineForApplicationChanges(ap //mark as timed out if not already marked timeline.Status = pipelineConfig.TIMELINE_STATUS_FETCH_TIMED_OUT timeline.StatusDetail = "Deployment timed out." - _, err, isTimelineUpdated = impl.SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId, timeline.Status, timeline, true) + _, err, isTimelineUpdated = impl.pipelineStatusTimelineService.SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId, timeline.Status, timeline, true) if err != nil { impl.logger.Errorw("error in saving pipeline status timeline", "err", err) return isTimelineUpdated, isTimelineTimedOut, kubectlApplySyncedTimeline, err @@ -876,40 +891,6 @@ func (impl *AppServiceImpl) UpdatePipelineStatusTimelineForApplicationChanges(ap return isTimelineUpdated, isTimelineTimedOut, kubectlApplySyncedTimeline, nil } -func (impl *AppServiceImpl) SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId int, timelineStatus pipelineConfig.TimelineStatus, timeline *pipelineConfig.PipelineStatusTimeline, isAppStore bool) (latestTimeline *pipelineConfig.PipelineStatusTimeline, err error, isTimelineUpdated bool) { - isTimelineUpdated = false - if isAppStore { - latestTimeline, err = impl.pipelineStatusTimelineRepository.FetchTimelineByInstalledAppVersionHistoryIdAndStatus(pipelineId, timelineStatus) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in getting latest timeline", "err", err) - return nil, err, isTimelineUpdated - } else if err == pg.ErrNoRows { - err = impl.pipelineStatusTimelineService.SaveTimeline(timeline, nil, true) - if err != nil { - impl.logger.Errorw("error in creating timeline status", "err", err, "timeline", timeline) - return nil, err, isTimelineUpdated - } - isTimelineUpdated = true - latestTimeline = timeline - } - } else { - latestTimeline, err = impl.pipelineStatusTimelineRepository.FetchTimelineByWfrIdAndStatus(pipelineId, timelineStatus) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in getting latest timeline", "err", err) - return nil, err, isTimelineUpdated - } else if err == pg.ErrNoRows { - err = impl.pipelineStatusTimelineService.SaveTimeline(timeline, nil, false) - if err != nil { - impl.logger.Errorw("error in creating timeline status", "err", err, "timeline", timeline) - return nil, err, isTimelineUpdated - } - isTimelineUpdated = true - latestTimeline = timeline - } - } - return latestTimeline, nil, isTimelineUpdated -} - func (impl *AppServiceImpl) WriteCDSuccessEvent(appId int, envId int, override *chartConfig.PipelineOverride) { event := impl.eventFactory.Build(util.Success, &override.PipelineId, appId, &envId, util.CD) impl.logger.Debugw("event WriteCDSuccessEvent", "event", event, "override", override) diff --git a/pkg/app/ManifestPushService.go b/pkg/app/ManifestPushService.go index 3f5634c4f9..7f370435e4 100644 --- a/pkg/app/ManifestPushService.go +++ b/pkg/app/ManifestPushService.go @@ -4,6 +4,7 @@ import ( "context" "fmt" bean2 "github.com/devtron-labs/devtron/api/bean" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/util" @@ -11,7 +12,6 @@ import ( "github.com/devtron-labs/devtron/pkg/app/bean" status2 "github.com/devtron-labs/devtron/pkg/app/status" chartService "github.com/devtron-labs/devtron/pkg/chart" - "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" "go.opentelemetry.io/otel" "go.uber.org/zap" @@ -27,12 +27,14 @@ type GitOpsPushService interface { } type GitOpsManifestPushServiceImpl struct { - logger *zap.SugaredLogger - chartTemplateService util.ChartTemplateService - chartService chartService.ChartService - gitOpsConfigRepository repository.GitOpsConfigRepository - gitFactory *GitFactory - pipelineStatusTimelineService status2.PipelineStatusTimelineService + logger *zap.SugaredLogger + chartTemplateService util.ChartTemplateService + chartService chartService.ChartService + gitOpsConfigRepository repository.GitOpsConfigRepository + gitFactory *GitFactory + pipelineStatusTimelineService status2.PipelineStatusTimelineService + pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository + acdConfig *argocdServer.ACDConfig } func NewGitOpsManifestPushServiceImpl( @@ -42,14 +44,18 @@ func NewGitOpsManifestPushServiceImpl( gitOpsConfigRepository repository.GitOpsConfigRepository, gitFactory *GitFactory, pipelineStatusTimelineService status2.PipelineStatusTimelineService, + pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository, + acdConfig *argocdServer.ACDConfig, ) *GitOpsManifestPushServiceImpl { return &GitOpsManifestPushServiceImpl{ - logger: logger, - chartTemplateService: chartTemplateService, - chartService: chartService, - gitOpsConfigRepository: gitOpsConfigRepository, - gitFactory: gitFactory, - pipelineStatusTimelineService: pipelineStatusTimelineService, + logger: logger, + chartTemplateService: chartTemplateService, + chartService: chartService, + gitOpsConfigRepository: gitOpsConfigRepository, + gitFactory: gitFactory, + pipelineStatusTimelineService: pipelineStatusTimelineService, + pipelineStatusTimelineRepository: pipelineStatusTimelineRepository, + acdConfig: acdConfig, } } @@ -72,9 +78,27 @@ func (impl *GitOpsManifestPushServiceImpl) PushChart(manifestPushTemplate *bean. manifestPushResponse.CommitHash = commitHash manifestPushResponse.CommitTime = commitTime - timeline := getTimelineObject(manifestPushTemplate, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.") - timelineErr := impl.pipelineStatusTimelineService.SaveTimeline(timeline, nil, false) - impl.logger.Errorw("Error in saving git commit success timeline", err, timelineErr) + dbConnection := impl.pipelineStatusTimelineRepository.GetConnection() + tx, err := dbConnection.Begin() + if err != nil { + impl.logger.Errorw("error in transaction begin in saving gitops timeline", "err", err) + manifestPushResponse.Error = err + return manifestPushResponse + } + + gitCommitTimeline := impl.pipelineStatusTimelineService.GetTimelineDbObjectByTimelineStatusAndTimelineDescription(manifestPushTemplate.WorkflowRunnerId, 0, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", manifestPushTemplate.UserId, time.Now()) + + timelines := []*pipelineConfig.PipelineStatusTimeline{gitCommitTimeline} + if !impl.acdConfig.ArgoCDAutoSyncEnabled { + // if manual sync is enabled, add ARGOCD_SYNC_INITIATED_TIMELINE + argoCDSyncInitiatedTimeline := impl.pipelineStatusTimelineService.GetTimelineDbObjectByTimelineStatusAndTimelineDescription(manifestPushTemplate.WorkflowRunnerId, 0, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED, "argocd sync initiated.", manifestPushTemplate.UserId, time.Now()) + timelines = append(timelines, argoCDSyncInitiatedTimeline) + } + timelineErr := impl.pipelineStatusTimelineService.SaveTimelines(timelines, tx) + if timelineErr != nil { + impl.logger.Errorw("Error in saving git commit success timeline", err, timelineErr) + } + tx.Commit() return manifestPushResponse } @@ -145,24 +169,9 @@ func (impl *GitOpsManifestPushServiceImpl) CommitValuesToGit(manifestPushTemplat } func (impl *GitOpsManifestPushServiceImpl) SaveTimelineForError(manifestPushTemplate *bean.ManifestPushTemplate, gitCommitErr error) { - timeline := getTimelineObject(manifestPushTemplate, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", gitCommitErr)) + timeline := impl.pipelineStatusTimelineService.GetTimelineDbObjectByTimelineStatusAndTimelineDescription(manifestPushTemplate.WorkflowRunnerId, 0, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", gitCommitErr), manifestPushTemplate.UserId, time.Now()) timelineErr := impl.pipelineStatusTimelineService.SaveTimeline(timeline, nil, false) if timelineErr != nil { impl.logger.Errorw("error in creating timeline status for git commit", "err", timelineErr, "timeline", timeline) } } - -func getTimelineObject(manifestPushTemplate *bean.ManifestPushTemplate, status string, statusDetail string) *pipelineConfig.PipelineStatusTimeline { - return &pipelineConfig.PipelineStatusTimeline{ - CdWorkflowRunnerId: manifestPushTemplate.WorkflowRunnerId, - Status: status, - StatusDetail: statusDetail, - StatusTime: time.Now(), - AuditLog: sql.AuditLog{ - CreatedBy: manifestPushTemplate.UserId, - CreatedOn: time.Now(), - UpdatedBy: manifestPushTemplate.UserId, - UpdatedOn: time.Now(), - }, - } -} diff --git a/pkg/app/status/PipelineStatusTimelineService.go b/pkg/app/status/PipelineStatusTimelineService.go index c50955c534..095a3ae163 100644 --- a/pkg/app/status/PipelineStatusTimelineService.go +++ b/pkg/app/status/PipelineStatusTimelineService.go @@ -16,7 +16,11 @@ type PipelineStatusTimelineService interface { SaveTimeline(timeline *pipelineConfig.PipelineStatusTimeline, tx *pg.Tx, isAppStore bool) error FetchTimelines(appId, envId, wfrId int, showTimeline bool) (*PipelineTimelineDetailDto, error) FetchTimelinesForAppStore(installedAppId, envId, installedAppVersionHistoryId int, showTimeline bool) (*PipelineTimelineDetailDto, error) - GetTimelineDbObjectByTimelineStatusAndTimelineDescription(cdWorkflowRunnerId int, timelineStatus pipelineConfig.TimelineStatus, timelineDescription string, userId int32) *pipelineConfig.PipelineStatusTimeline + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(cdWorkflowRunnerId int, installedAppVersionHistoryId int, timelineStatus pipelineConfig.TimelineStatus, timelineDescription string, userId int32, statusTime time.Time) *pipelineConfig.PipelineStatusTimeline + SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId int, timelineStatus pipelineConfig.TimelineStatus, timeline *pipelineConfig.PipelineStatusTimeline, isAppStore bool) (latestTimeline *pipelineConfig.PipelineStatusTimeline, err error, isTimelineUpdated bool) + GetArgoAppSyncStatus(cdWfrId int) bool + GetArgoAppSyncStatusForAppStore(installedAppVersionHistoryId int) bool + SaveTimelines(timeline []*pipelineConfig.PipelineStatusTimeline, tx *pg.Tx) error } type PipelineStatusTimelineServiceImpl struct { @@ -105,12 +109,13 @@ func (impl *PipelineStatusTimelineServiceImpl) SaveTimeline(timeline *pipelineCo } return nil } -func (impl *PipelineStatusTimelineServiceImpl) GetTimelineDbObjectByTimelineStatusAndTimelineDescription(cdWorkflowRunnerId int, timelineStatus pipelineConfig.TimelineStatus, timelineDescription string, userId int32) *pipelineConfig.PipelineStatusTimeline { +func (impl *PipelineStatusTimelineServiceImpl) GetTimelineDbObjectByTimelineStatusAndTimelineDescription(cdWorkflowRunnerId int, installedAppVersionHistoryId int, timelineStatus pipelineConfig.TimelineStatus, timelineDescription string, userId int32, statusTime time.Time) *pipelineConfig.PipelineStatusTimeline { timeline := &pipelineConfig.PipelineStatusTimeline{ - CdWorkflowRunnerId: cdWorkflowRunnerId, - Status: timelineStatus, - StatusDetail: timelineDescription, - StatusTime: time.Now(), + CdWorkflowRunnerId: cdWorkflowRunnerId, + InstalledAppVersionHistoryId: installedAppVersionHistoryId, + Status: timelineStatus, + StatusDetail: timelineDescription, + StatusTime: time.Now(), AuditLog: sql.AuditLog{ CreatedBy: userId, CreatedOn: time.Now(), @@ -329,3 +334,69 @@ func (impl *PipelineStatusTimelineServiceImpl) FetchTimelinesForAppStore(install } return timelineDetail, nil } + +func (impl *PipelineStatusTimelineServiceImpl) SavePipelineStatusTimelineIfNotAlreadyPresent(pipelineId int, timelineStatus pipelineConfig.TimelineStatus, timeline *pipelineConfig.PipelineStatusTimeline, isAppStore bool) (latestTimeline *pipelineConfig.PipelineStatusTimeline, err error, isTimelineUpdated bool) { + isTimelineUpdated = false + if isAppStore { + latestTimeline, err = impl.pipelineStatusTimelineRepository.FetchTimelineByInstalledAppVersionHistoryIdAndStatus(pipelineId, timelineStatus) + if err != nil && err != pg.ErrNoRows { + impl.logger.Errorw("error in getting latest timeline", "err", err) + return nil, err, isTimelineUpdated + } else if err == pg.ErrNoRows { + err = impl.SaveTimeline(timeline, nil, true) + if err != nil { + impl.logger.Errorw("error in creating timeline status", "err", err, "timeline", timeline) + return nil, err, isTimelineUpdated + } + isTimelineUpdated = true + latestTimeline = timeline + } + } else { + latestTimeline, err = impl.pipelineStatusTimelineRepository.FetchTimelineByWfrIdAndStatus(pipelineId, timelineStatus) + if err != nil && err != pg.ErrNoRows { + impl.logger.Errorw("error in getting latest timeline", "err", err) + return nil, err, isTimelineUpdated + } else if err == pg.ErrNoRows { + err = impl.SaveTimeline(timeline, nil, false) + if err != nil { + impl.logger.Errorw("error in creating timeline status", "err", err, "timeline", timeline) + return nil, err, isTimelineUpdated + } + isTimelineUpdated = true + latestTimeline = timeline + } + } + return latestTimeline, nil, isTimelineUpdated +} + +func (impl *PipelineStatusTimelineServiceImpl) GetArgoAppSyncStatus(cdWfrId int) bool { + timeline, err := impl.pipelineStatusTimelineRepository.FetchTimelineByWfrIdAndStatus(cdWfrId, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED) + if err != nil { + impl.logger.Errorw("error in fetching argocd sync status", "err", err) + return false + } + if timeline != nil && timeline.Id == 0 { + return false + } + return true +} + +func (impl *PipelineStatusTimelineServiceImpl) GetArgoAppSyncStatusForAppStore(installedAppVersionHistoryId int) bool { + timeline, err := impl.pipelineStatusTimelineRepository.FetchTimelineByInstalledAppVersionHistoryIdAndStatus(installedAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED) + if err != nil { + impl.logger.Errorw("error in fetching argocd sync status", "err", err) + return false + } + if timeline != nil && timeline.Id == 0 { + return false + } + return true +} + +func (impl *PipelineStatusTimelineServiceImpl) SaveTimelines(timeline []*pipelineConfig.PipelineStatusTimeline, tx *pg.Tx) error { + _, err := tx.Model(&timeline).Insert() + if err != nil { + return err + } + return err +} diff --git a/pkg/appStore/deployment/fullMode/AppStoreDeploymentFullModeService.go b/pkg/appStore/deployment/fullMode/AppStoreDeploymentFullModeService.go index 4d8f05d664..0899e6d7d0 100644 --- a/pkg/appStore/deployment/fullMode/AppStoreDeploymentFullModeService.go +++ b/pkg/appStore/deployment/fullMode/AppStoreDeploymentFullModeService.go @@ -20,6 +20,7 @@ package appStoreDeploymentFullMode import ( "context" "encoding/json" + "errors" "fmt" "github.com/devtron-labs/common-lib/pubsub-lib" "github.com/devtron-labs/common-lib/pubsub-lib/model" @@ -62,7 +63,7 @@ const ( type AppStoreDeploymentFullModeService interface { AppStoreDeployOperationGIT(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, *util.ChartGitAttribute, error) - AppStoreDeployOperationACD(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, chartGitAttr *util.ChartGitAttribute, ctx context.Context) (*appStoreBean.InstallAppVersionDTO, error) + AppStoreDeployOperationACD(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, chartGitAttr *util.ChartGitAttribute, ctx context.Context, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, error) RegisterInArgo(chartGitAttribute *util.ChartGitAttribute, ctx context.Context) error SyncACD(acdAppName string, ctx context.Context) UpdateValuesYaml(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, error) @@ -92,6 +93,7 @@ type AppStoreDeploymentFullModeServiceImpl struct { argoClientWrapperService argocdServer.ArgoClientWrapperService pubSubClient *pubsub_lib.PubSubClientServiceImpl installedAppRepositoryHistory repository4.InstalledAppVersionHistoryRepository + ACDConfig *argocdServer.ACDConfig } func NewAppStoreDeploymentFullModeServiceImpl(logger *zap.SugaredLogger, @@ -110,6 +112,7 @@ func NewAppStoreDeploymentFullModeServiceImpl(logger *zap.SugaredLogger, argoClientWrapperService argocdServer.ArgoClientWrapperService, pubSubClient *pubsub_lib.PubSubClientServiceImpl, installedAppRepositoryHistory repository4.InstalledAppVersionHistoryRepository, + ACDConfig *argocdServer.ACDConfig, ) *AppStoreDeploymentFullModeServiceImpl { appStoreDeploymentFullModeServiceImpl := &AppStoreDeploymentFullModeServiceImpl{ logger: logger, @@ -132,6 +135,7 @@ func NewAppStoreDeploymentFullModeServiceImpl(logger *zap.SugaredLogger, argoClientWrapperService: argoClientWrapperService, pubSubClient: pubSubClient, installedAppRepositoryHistory: installedAppRepositoryHistory, + ACDConfig: ACDConfig, } err := appStoreDeploymentFullModeServiceImpl.SubscribeHelmInstallStatus() if err != nil { @@ -194,7 +198,7 @@ func (impl AppStoreDeploymentFullModeServiceImpl) AppStoreDeployOperationGIT(ins } gitOpsRepoName := impl.chartTemplateService.GetGitOpsRepoName(installAppVersionRequest.AppName) - //getting user name & emailId for commit author data + //getting username & emailId for commit author data userEmailId, userName := impl.chartTemplateService.GetUserEmailIdAndNameForGitOpsCommit(installAppVersionRequest.UserId) gitOpsConfigBitbucket, err := impl.gitOpsConfigRepository.GetGitOpsConfigByProvider(util.BITBUCKET_PROVIDER) if err != nil { @@ -315,7 +319,7 @@ func (impl AppStoreDeploymentFullModeServiceImpl) AppStoreDeployOperationGIT(ins return installAppVersionRequest, chartGitAttr, nil } -func (impl AppStoreDeploymentFullModeServiceImpl) AppStoreDeployOperationACD(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, chartGitAttr *util.ChartGitAttribute, ctx context.Context) (*appStoreBean.InstallAppVersionDTO, error) { +func (impl AppStoreDeploymentFullModeServiceImpl) AppStoreDeployOperationACD(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, chartGitAttr *util.ChartGitAttribute, ctx context.Context, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, error) { ctx, cancel := context.WithTimeout(ctx, 1*time.Minute) defer cancel() //STEP 4: registerInArgo @@ -334,9 +338,29 @@ func (impl AppStoreDeploymentFullModeServiceImpl) AppStoreDeployOperationACD(ins //impl.SyncACD(installAppVersionRequest.ACDAppName, ctx) //STEP 7: normal refresh ACD - update for step 6 to avoid delay - err = impl.argoClientWrapperService.GetArgoAppWithNormalRefresh(ctx, installAppVersionRequest.ACDAppName) + syncTime := time.Now() + err = impl.argoClientWrapperService.SyncArgoCDApplicationIfNeededAndRefresh(ctx, installAppVersionRequest.ACDAppName) if err != nil { impl.logger.Errorw("error in getting the argo application with normal refresh", "err", err) + return nil, err + } + if !impl.ACDConfig.ArgoCDAutoSyncEnabled { + timeline := &pipelineConfig.PipelineStatusTimeline{ + InstalledAppVersionHistoryId: installAppVersionRequest.InstalledAppVersionHistoryId, + Status: pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED, + StatusDetail: "argocd sync completed.", + StatusTime: syncTime, + AuditLog: sql.AuditLog{ + CreatedBy: installAppVersionRequest.UserId, + CreatedOn: time.Now(), + UpdatedBy: installAppVersionRequest.UserId, + UpdatedOn: time.Now(), + }, + } + err = impl.pipelineStatusTimelineService.SaveTimeline(timeline, tx, true) + if err != nil { + impl.logger.Errorw("error in creating timeline for argocd sync", "err", err, "timeline", timeline) + } } return installAppVersionRequest, nil @@ -371,7 +395,6 @@ func (impl AppStoreDeploymentFullModeServiceImpl) createInArgo(chartGitAttribute if appNamespace == "" { appNamespace = "default" } - appreq := &argocdServer.AppTemplate{ ApplicationName: argocdAppName, Namespace: impl.aCDAuthConfig.ACDConfigMapNamespace, @@ -381,15 +404,14 @@ func (impl AppStoreDeploymentFullModeServiceImpl) createInArgo(chartGitAttribute ValuesFile: fmt.Sprintf("values.yaml"), RepoPath: chartGitAttribute.ChartLocation, RepoUrl: chartGitAttribute.RepoUrl, + AutoSyncEnabled: impl.ACDConfig.ArgoCDAutoSyncEnabled, } - _, err := impl.ArgoK8sClient.CreateAcdApp(appreq, envModel.Cluster) - + _, err := impl.ArgoK8sClient.CreateAcdApp(appreq, envModel.Cluster, argocdServer.ARGOCD_APPLICATION_TEMPLATE) //create if err != nil { impl.logger.Errorw("error in creating argo cd app ", "err", err) return err } - return nil } @@ -430,51 +452,11 @@ func (impl AppStoreDeploymentFullModeServiceImpl) UpdateValuesYaml(installAppVer } commitHash, err := impl.appStoreDeploymentCommonService.CommitConfigToGit(valuesGitConfig) - if err != nil { - impl.logger.Errorw("error in values commit", "err", err) - } - - isAppStore := true if err != nil { impl.logger.Errorw("error in git commit", "err", err) - //update timeline status for git commit failed state - gitCommitStatus := pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED - gitCommitStatusDetail := fmt.Sprintf("Git commit failed - %v", err) - timeline := &pipelineConfig.PipelineStatusTimeline{ - InstalledAppVersionHistoryId: installAppVersionRequest.InstalledAppVersionHistoryId, - Status: gitCommitStatus, - StatusDetail: gitCommitStatusDetail, - StatusTime: time.Now(), - AuditLog: sql.AuditLog{ - CreatedBy: installAppVersionRequest.UserId, - CreatedOn: time.Now(), - UpdatedBy: installAppVersionRequest.UserId, - UpdatedOn: time.Now(), - }, - } - timelineErr := impl.pipelineStatusTimelineService.SaveTimeline(timeline, tx, isAppStore) - if timelineErr != nil { - impl.logger.Errorw("error in creating timeline status for git commit", "err", timelineErr, "timeline", timeline) - } - return installAppVersionRequest, err + return installAppVersionRequest, errors.New(pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED) } //update timeline status for git commit state - timeline := &pipelineConfig.PipelineStatusTimeline{ - InstalledAppVersionHistoryId: installAppVersionRequest.InstalledAppVersionHistoryId, - Status: pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, - StatusDetail: "Git commit done successfully.", - StatusTime: time.Now(), - AuditLog: sql.AuditLog{ - CreatedBy: installAppVersionRequest.UserId, - CreatedOn: time.Now(), - UpdatedBy: installAppVersionRequest.UserId, - UpdatedOn: time.Now(), - }, - } - err = impl.pipelineStatusTimelineService.SaveTimeline(timeline, tx, isAppStore) - if err != nil { - impl.logger.Errorw("error in creating timeline status for deployment initiation for update of installedAppVersionHistoryId", "err", err, "installedAppVersionHistoryId", installAppVersionRequest.InstalledAppVersionHistoryId) - } installAppVersionRequest.GitHash = commitHash return installAppVersionRequest, nil } @@ -496,7 +478,7 @@ func (impl AppStoreDeploymentFullModeServiceImpl) UpdateRequirementYaml(installA _, err = impl.appStoreDeploymentCommonService.CommitConfigToGit(requirementsGitConfig) if err != nil { impl.logger.Errorw("error in values commit", "err", err) - return err + return errors.New(pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED) } return nil diff --git a/pkg/appStore/deployment/repository/InstalledAppVersionHistory.go b/pkg/appStore/deployment/repository/InstalledAppVersionHistory.go index 52ece2aae0..f914c749ac 100644 --- a/pkg/appStore/deployment/repository/InstalledAppVersionHistory.go +++ b/pkg/appStore/deployment/repository/InstalledAppVersionHistory.go @@ -20,7 +20,7 @@ type InstalledAppVersionHistoryRepository interface { FindPreviousInstalledAppVersionHistoryByStatus(installedAppVersionId int, installedAppVersionHistoryId int, status []string) ([]*InstalledAppVersionHistory, error) UpdateInstalledAppVersionHistoryWithTxn(models []*InstalledAppVersionHistory, tx *pg.Tx) error GetAppStoreApplicationVersionIdByInstalledAppVersionHistoryId(installedAppVersionHistoryId int) (int, error) - + UpdateGitHash(installedAppVersionHistoryId int, gitHash string, tx *pg.Tx) error GetConnection() *pg.DB } @@ -163,6 +163,15 @@ func (impl InstalledAppVersionHistoryRepositoryImpl) FindPreviousInstalledAppVer return iavr, err } +func (impl InstalledAppVersionHistoryRepositoryImpl) UpdateGitHash(installedAppVersionHistoryId int, gitHash string, tx *pg.Tx) error { + query := "update installed_app_version_history set git_hash=? where id=?" + _, err := tx.Exec(query, gitHash, installedAppVersionHistoryId) + if err != nil { + return err + } + return nil +} + func (impl InstalledAppVersionHistoryRepositoryImpl) GetConnection() *pg.DB { return impl.dbConnection } diff --git a/pkg/appStore/deployment/service/AppStoreDeploymentService.go b/pkg/appStore/deployment/service/AppStoreDeploymentService.go index 602020c9d0..02e55ca006 100644 --- a/pkg/appStore/deployment/service/AppStoreDeploymentService.go +++ b/pkg/appStore/deployment/service/AppStoreDeploymentService.go @@ -26,6 +26,7 @@ import ( client "github.com/devtron-labs/devtron/api/helm-app" openapi "github.com/devtron-labs/devtron/api/helm-app/openapiClient" openapi2 "github.com/devtron-labs/devtron/api/openapi/openapiClient" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/internal/constants" repository2 "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/internal/sql/repository/app" @@ -67,7 +68,7 @@ type AppStoreDeploymentService interface { GetDeploymentHistory(ctx context.Context, installedApp *appStoreBean.InstallAppVersionDTO) (*client.DeploymentHistoryAndInstalledAppInfo, error) GetDeploymentHistoryInfo(ctx context.Context, installedApp *appStoreBean.InstallAppVersionDTO, installedAppVersionHistoryId int) (*openapi.HelmAppDeploymentManifestDetail, error) UpdateInstalledApp(ctx context.Context, installAppVersionRequest *appStoreBean.InstallAppVersionDTO) (*appStoreBean.InstallAppVersionDTO, error) - UpdateInstalledAppVersionHistoryWithGitHash(installAppVersionRequest *appStoreBean.InstallAppVersionDTO) error + UpdateInstalledAppVersionHistoryWithGitHash(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, tx *pg.Tx) error GetInstalledAppVersion(id int, userId int32) (*appStoreBean.InstallAppVersionDTO, error) InstallAppByHelm(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ctx context.Context) (*appStoreBean.InstallAppVersionDTO, error) UpdateProjectHelmApp(updateAppRequest *appStoreBean.UpdateProjectHelmAppDTO) error @@ -106,6 +107,7 @@ type AppStoreDeploymentServiceImpl struct { gitOpsRepository repository2.GitOpsConfigRepository deploymentTypeConfig *DeploymentServiceTypeConfig ChartTemplateService util.ChartTemplateService + aCDConfig *argocdServer.ACDConfig } func NewAppStoreDeploymentServiceImpl(logger *zap.SugaredLogger, installedAppRepository repository.InstalledAppRepository, @@ -116,7 +118,7 @@ func NewAppStoreDeploymentServiceImpl(logger *zap.SugaredLogger, installedAppRep clusterService cluster.ClusterService, helmAppService client.HelmAppService, appStoreDeploymentCommonService appStoreDeploymentCommon.AppStoreDeploymentCommonService, globalEnvVariables *util2.GlobalEnvVariables, installedAppRepositoryHistory repository.InstalledAppVersionHistoryRepository, gitOpsRepository repository2.GitOpsConfigRepository, attributesService attributes.AttributesService, - deploymentTypeConfig *DeploymentServiceTypeConfig, ChartTemplateService util.ChartTemplateService) *AppStoreDeploymentServiceImpl { + deploymentTypeConfig *DeploymentServiceTypeConfig, ChartTemplateService util.ChartTemplateService, aCDConfig *argocdServer.ACDConfig) *AppStoreDeploymentServiceImpl { appStoreDeploymentServiceImpl := &AppStoreDeploymentServiceImpl{ logger: logger, @@ -137,6 +139,7 @@ func NewAppStoreDeploymentServiceImpl(logger *zap.SugaredLogger, installedAppRep gitOpsRepository: gitOpsRepository, deploymentTypeConfig: deploymentTypeConfig, ChartTemplateService: ChartTemplateService, + aCDConfig: aCDConfig, } return appStoreDeploymentServiceImpl } @@ -405,7 +408,7 @@ func (impl AppStoreDeploymentServiceImpl) InstallApp(installAppVersionRequest *a impl.updateDeploymentParametersInRequest(installAppVersionRequest, installAppVersionRequest.DeploymentAppType) if util.IsAcdApp(installAppVersionRequest.DeploymentAppType) || util.IsManifestDownload(installAppVersionRequest.DeploymentAppType) { - _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_INITIATED, "Deployment initiated successfully.", tx) + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_INITIATED, "Deployment initiated successfully.", time.Now(), tx) } manifest, err := impl.appStoreDeploymentCommonService.GenerateManifest(installAppVersionRequest) @@ -415,7 +418,7 @@ func (impl AppStoreDeploymentServiceImpl) InstallApp(installAppVersionRequest *a } if installAppVersionRequest.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_MANIFEST_DOWNLOAD { - _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_DESCRIPTION_MANIFEST_GENERATED, "Manifest generated successfully.", tx) + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_DESCRIPTION_MANIFEST_GENERATED, "Manifest generated successfully.", time.Now(), tx) } var gitOpsResponse *appStoreDeploymentCommon.AppStoreGitOpsResponse @@ -424,14 +427,24 @@ func (impl AppStoreDeploymentServiceImpl) InstallApp(installAppVersionRequest *a if err != nil { impl.logger.Errorw("error in doing gitops operation", "err", err) if util.IsAcdApp(installAppVersionRequest.DeploymentAppType) { - _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", err), tx) + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", err), time.Now(), tx) } return nil, err } if util.IsAcdApp(installAppVersionRequest.DeploymentAppType) { - _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", tx) + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", time.Now(), tx) + if !impl.aCDConfig.ArgoCDAutoSyncEnabled { + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED, "argocd sync initiated.", time.Now(), tx) + } } installAppVersionRequest.GitHash = gitOpsResponse.GitHash + if len(installAppVersionRequest.GitHash) > 0 { + err = impl.installedAppRepositoryHistory.UpdateGitHash(installAppVersionRequest.InstalledAppVersionHistoryId, gitOpsResponse.GitHash, tx) + if err != nil { + impl.logger.Errorw("error in updating git hash ", "err", err) + return nil, err + } + } } if util2.IsBaseStack() || util2.IsHelmApp(installAppVersionRequest.AppOfferingMode) || util.IsHelmApp(installAppVersionRequest.DeploymentAppType) { @@ -509,29 +522,16 @@ func (impl AppStoreDeploymentServiceImpl) UpdateInstallAppVersionHistory(install } return installedAppVersionHistory, nil } -func (impl AppStoreDeploymentServiceImpl) UpdateInstalledAppVersionHistoryWithGitHash(installAppVersionRequest *appStoreBean.InstallAppVersionDTO) error { - dbConnection := impl.installedAppRepository.GetConnection() - tx, err := dbConnection.Begin() - if err != nil { - return err - } - // Rollback tx on error. - defer tx.Rollback() +func (impl AppStoreDeploymentServiceImpl) UpdateInstalledAppVersionHistoryWithGitHash(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, tx *pg.Tx) error { savedInstalledAppVersionHistory, err := impl.installedAppRepositoryHistory.GetInstalledAppVersionHistory(installAppVersionRequest.InstalledAppVersionHistoryId) savedInstalledAppVersionHistory.GitHash = installAppVersionRequest.GitHash savedInstalledAppVersionHistory.UpdatedOn = time.Now() savedInstalledAppVersionHistory.UpdatedBy = installAppVersionRequest.UserId - _, err = impl.installedAppRepositoryHistory.UpdateInstalledAppVersionHistory(savedInstalledAppVersionHistory, tx) if err != nil { impl.logger.Errorw("error while fetching from db", "error", err) return err } - err = tx.Commit() - if err != nil { - impl.logger.Errorw("error while committing transaction to db", "error", err) - return err - } return nil } @@ -938,14 +938,6 @@ func (impl AppStoreDeploymentServiceImpl) RollbackApplication(ctx context.Contex return false, err } - if installedApp.AppOfferingMode == util2.SERVER_MODE_FULL { - // create build history for version upgrade, chart upgrade or simple update - err = impl.UpdateInstalledAppVersionHistoryWithGitHash(installedApp) - if err != nil { - impl.logger.Errorw("error on creating history for chart deployment", "error", err) - return false, err - } - } err1 := impl.UpdatePreviousDeploymentStatusForAppStore(installedApp, triggeredAt, err) if err1 != nil { impl.logger.Errorw("error while update previous installed app version history", "err", err, "installAppVersionRequest", installedApp) @@ -1035,13 +1027,6 @@ func (impl AppStoreDeploymentServiceImpl) installAppPostDbOperation(installAppVe } //step 5 create build history first entry for install app version for argocd or helm type deployments - if len(installAppVersionRequest.GitHash) > 0 { - err = impl.UpdateInstalledAppVersionHistoryWithGitHash(installAppVersionRequest) - if err != nil { - impl.logger.Errorw("error in installAppPostDbOperation", "err", err) - return err - } - } if !impl.deploymentTypeConfig.HelmInstallASyncMode { err = impl.updateInstalledAppVersionHistoryWithSync(installAppVersionRequest) if err != nil { @@ -1436,7 +1421,7 @@ func (impl *AppStoreDeploymentServiceImpl) UpdateInstalledApp(ctx context.Contex return nil, err } installAppVersionRequest.InstalledAppVersionHistoryId = installedAppVersionHistory.Id - _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_INITIATED, "Deployment initiated successfully.", tx) + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_INITIATED, "Deployment initiated successfully.", time.Now(), tx) manifest, err := impl.appStoreDeploymentCommonService.GenerateManifest(installAppVersionRequest) if err != nil { @@ -1445,7 +1430,7 @@ func (impl *AppStoreDeploymentServiceImpl) UpdateInstalledApp(ctx context.Contex return nil, err } if installAppVersionRequest.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_MANIFEST_DOWNLOAD { - _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_DESCRIPTION_MANIFEST_GENERATED, "Manifest generated successfully.", tx) + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_DESCRIPTION_MANIFEST_GENERATED, "Manifest generated successfully.", time.Now(), tx) } // gitOps operation monoRepoMigrationRequired := false @@ -1512,18 +1497,26 @@ func (impl *AppStoreDeploymentServiceImpl) UpdateInstalledApp(ctx context.Contex if createRepoErr != nil || requirementsCommitErr != nil || valuesCommitErr != nil { impl.logger.Errorw("error in doing gitops operation", "err", err) - _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", err), tx) + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", err), time.Now(), tx) return nil, err } installAppVersionRequest.GitHash = gitHash - _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", tx) - + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", time.Now(), tx) + if !impl.aCDConfig.ArgoCDAutoSyncEnabled { + _ = impl.appStoreDeploymentArgoCdService.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED, "Argocd sync initiated", time.Now(), tx) + } + installedAppVersionHistory.GitHash = gitHash + _, err = impl.installedAppRepositoryHistory.UpdateInstalledAppVersionHistory(installedAppVersionHistory, tx) + if err != nil { + impl.logger.Errorw("error on updating history for chart deployment", "error", err, "installedAppVersion", installedAppVersion) + return nil, err + } } if installAppVersionRequest.PerformACDDeployment { // refresh update repo details on ArgoCD if repo is changed - err = impl.appStoreDeploymentArgoCdService.RefreshAndUpdateACDApp(installAppVersionRequest, gitOpsResponse.ChartGitAttribute, monoRepoMigrationRequired, ctx) + err = impl.appStoreDeploymentArgoCdService.UpdateAndSyncACDApps(installAppVersionRequest, gitOpsResponse.ChartGitAttribute, monoRepoMigrationRequired, ctx, tx) if err != nil { impl.logger.Errorw("error in acd patch request", "err", err) return nil, err @@ -1552,13 +1545,7 @@ func (impl *AppStoreDeploymentServiceImpl) UpdateInstalledApp(ctx context.Contex return nil, err } - if util.IsAcdApp(installAppVersionRequest.DeploymentAppType) { - err = impl.UpdateInstalledAppVersionHistoryWithGitHash(installAppVersionRequest) - if err != nil { - impl.logger.Errorw("error on updating history for chart deployment", "error", err, "installedAppVersion", installedAppVersion) - return nil, err - } - } else if util.IsManifestDownload(installAppVersionRequest.DeploymentAppType) { + if util.IsManifestDownload(installAppVersionRequest.DeploymentAppType) { err = impl.UpdateInstalledAppVersionHistoryStatus(installAppVersionRequest, pipelineConfig.WorkflowSucceeded) if err != nil { impl.logger.Errorw("error on creating history for chart deployment", "error", err) diff --git a/pkg/appStore/deployment/service/InstalledAppService.go b/pkg/appStore/deployment/service/InstalledAppService.go index a055fe1840..e540b4f323 100644 --- a/pkg/appStore/deployment/service/InstalledAppService.go +++ b/pkg/appStore/deployment/service/InstalledAppService.go @@ -139,6 +139,7 @@ type InstalledAppServiceImpl struct { appStoreDeploymentCommonService appStoreDeploymentCommon.AppStoreDeploymentCommonService k8sCommonService k8s.K8sCommonService k8sApplicationService application3.K8sApplicationService + acdConfig *argocdServer.ACDConfig } func NewInstalledAppServiceImpl(logger *zap.SugaredLogger, @@ -163,7 +164,8 @@ func NewInstalledAppServiceImpl(logger *zap.SugaredLogger, appStatusService appStatus.AppStatusService, K8sUtil *util4.K8sUtil, pipelineStatusTimelineService status.PipelineStatusTimelineService, appStoreDeploymentCommonService appStoreDeploymentCommon.AppStoreDeploymentCommonService, - appStoreDeploymentArgoCdService appStoreDeploymentGitopsTool.AppStoreDeploymentArgoCdService, k8sCommonService k8s.K8sCommonService, k8sApplicationService application3.K8sApplicationService) (*InstalledAppServiceImpl, error) { + appStoreDeploymentArgoCdService appStoreDeploymentGitopsTool.AppStoreDeploymentArgoCdService, k8sCommonService k8s.K8sCommonService, k8sApplicationService application3.K8sApplicationService, + acdConfig *argocdServer.ACDConfig) (*InstalledAppServiceImpl, error) { impl := &InstalledAppServiceImpl{ logger: logger, installedAppRepository: installedAppRepository, @@ -198,6 +200,7 @@ func NewInstalledAppServiceImpl(logger *zap.SugaredLogger, appStoreDeploymentCommonService: appStoreDeploymentCommonService, k8sCommonService: k8sCommonService, k8sApplicationService: k8sApplicationService, + acdConfig: acdConfig, } err := impl.Subscribe() if err != nil { @@ -416,6 +419,7 @@ func (impl InstalledAppServiceImpl) performDeployStageOnAcd(installedAppVersion _ = impl.pipelineStatusTimelineService.SaveTimeline(timeline, nil, true) return nil, err } + timeline := &pipelineConfig.PipelineStatusTimeline{ InstalledAppVersionHistoryId: installedAppVersion.InstalledAppVersionHistoryId, Status: pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, @@ -435,6 +439,35 @@ func (impl InstalledAppServiceImpl) performDeployStageOnAcd(installedAppVersion impl.logger.Errorw(" error", "err", err) return nil, err } + + GitCommitSuccessTimeline := impl.pipelineStatusTimelineService. + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedAppVersion.InstalledAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", installedAppVersion.UserId, time.Now()) + + timelines := []*pipelineConfig.PipelineStatusTimeline{GitCommitSuccessTimeline} + if !impl.acdConfig.ArgoCDAutoSyncEnabled { + ArgocdSyncInitiatedTimeline := impl.pipelineStatusTimelineService. + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedAppVersion.InstalledAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED, "ArgoCD sync initiated.", installedAppVersion.UserId, time.Now()) + + timelines = append(timelines, ArgocdSyncInitiatedTimeline) + } + + dbConnection := impl.installedAppRepository.GetConnection() + tx, err := dbConnection.Begin() + if err != nil { + impl.logger.Errorw("error in getting db connection for saving timelines", "err", err) + return nil, err + } + err = impl.pipelineStatusTimelineService.SaveTimelines(timelines, tx) + if err != nil { + impl.logger.Errorw("error in creating timeline status for deployment initiation for update of installedAppVersionHistoryId", "err", err, "installedAppVersionHistoryId", installedAppVersion.InstalledAppVersionHistoryId) + } + tx.Commit() + // update build history for chart for argo_cd apps + err = impl.appStoreDeploymentService.UpdateInstalledAppVersionHistoryWithGitHash(installedAppVersion, nil) + if err != nil { + impl.logger.Errorw("error on updating history for chart deployment", "error", err, "installedAppVersion", installedAppVersion) + return nil, err + } installedAppVersion.GitHash = appStoreGitOpsResponse.GitHash chartGitAttr.RepoUrl = appStoreGitOpsResponse.ChartGitAttribute.RepoUrl chartGitAttr.ChartLocation = appStoreGitOpsResponse.ChartGitAttribute.ChartLocation @@ -477,7 +510,7 @@ func (impl InstalledAppServiceImpl) performDeployStageOnAcd(installedAppVersion installedAppVersion.Status == appStoreBean.GIT_SUCCESS || installedAppVersion.Status == appStoreBean.ACD_ERROR { //step 3 acd operation register, sync - _, err := impl.appStoreDeploymentFullModeService.AppStoreDeployOperationACD(installedAppVersion, chartGitAttr, ctx) + _, err := impl.appStoreDeploymentFullModeService.AppStoreDeployOperationACD(installedAppVersion, chartGitAttr, ctx, nil) if err != nil { impl.logger.Errorw("error", "chartGitAttr", chartGitAttr, "err", err) _, err = impl.appStoreDeploymentService.AppStoreDeployOperationStatusUpdate(installedAppVersion.InstalledAppId, appStoreBean.ACD_ERROR) @@ -555,15 +588,6 @@ func (impl InstalledAppServiceImpl) performDeployStage(installedAppVersionId int return nil, err } - if util.IsAcdApp(installedAppVersion.DeploymentAppType) { - // update build history for chart for argo_cd apps - err = impl.appStoreDeploymentService.UpdateInstalledAppVersionHistoryWithGitHash(installedAppVersion) - if err != nil { - impl.logger.Errorw("error on updating history for chart deployment", "error", err, "installedAppVersion", installedAppVersion) - return nil, err - } - } - return installedAppVersion, nil } diff --git a/pkg/appStore/deployment/tool/AppStoreDeploymentHelmService.go b/pkg/appStore/deployment/tool/AppStoreDeploymentHelmService.go index a2fab88ef5..9716abb607 100644 --- a/pkg/appStore/deployment/tool/AppStoreDeploymentHelmService.go +++ b/pkg/appStore/deployment/tool/AppStoreDeploymentHelmService.go @@ -35,7 +35,7 @@ type AppStoreDeploymentHelmService interface { UpdateInstalledApp(ctx context.Context, installAppVersionRequest *appStoreBean.InstallAppVersionDTO, environment *clusterRepository.Environment, installedAppVersion *repository.InstalledAppVersions, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, error) DeleteDeploymentApp(ctx context.Context, appName string, environmentName string, installAppVersionRequest *appStoreBean.InstallAppVersionDTO) error UpdateInstalledAppAndPipelineStatusForFailedDeploymentStatus(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, triggeredAt time.Time, err error) error - SaveTimelineForACDHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status string, statusDetail string, tx *pg.Tx) error + SaveTimelineForACDHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status string, statusDetail string, statusTime time.Time, tx *pg.Tx) error UpdateChartInfo(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *util.ChartGitAttribute, installedAppVersionHistoryId int, ctx context.Context) error } @@ -465,7 +465,7 @@ func (impl *AppStoreDeploymentHelmServiceImpl) DeleteDeploymentApp(ctx context.C return nil } -func (impl *AppStoreDeploymentHelmServiceImpl) SaveTimelineForACDHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status string, statusDetail string, tx *pg.Tx) error { +func (impl *AppStoreDeploymentHelmServiceImpl) SaveTimelineForACDHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status string, statusDetail string, statusTime time.Time, tx *pg.Tx) error { return nil } @@ -476,6 +476,6 @@ func (impl *AppStoreDeploymentHelmServiceImpl) UpdateInstalledAppAndPipelineStat // TODO: Need to refactor this,refer below reason // This is being done as in ea mode wire argocd service is being binded to helmServiceImpl due to which we are restricted to implement this here. // RefreshAndUpdateACDApp this will update chart info in acd app if required in case of mono repo migration and will refresh argo app -func (impl *AppStoreDeploymentHelmServiceImpl) RefreshAndUpdateACDApp(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *util.ChartGitAttribute, isMonoRepoMigrationRequired bool, ctx context.Context) error { +func (impl *AppStoreDeploymentHelmServiceImpl) UpdateAndSyncACDApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *util.ChartGitAttribute, isMonoRepoMigrationRequired bool, ctx context.Context, tx *pg.Tx) error { return errors.New("this is not implemented") } diff --git a/pkg/appStore/deployment/tool/gitops/AppStoreDeploymentArgoCdService.go b/pkg/appStore/deployment/tool/gitops/AppStoreDeploymentArgoCdService.go index 4f79628c81..a29a088aba 100644 --- a/pkg/appStore/deployment/tool/gitops/AppStoreDeploymentArgoCdService.go +++ b/pkg/appStore/deployment/tool/gitops/AppStoreDeploymentArgoCdService.go @@ -54,9 +54,9 @@ type AppStoreDeploymentArgoCdService interface { UpdateInstalledApp(ctx context.Context, installAppVersionRequest *appStoreBean.InstallAppVersionDTO, environment *clusterRepository.Environment, installedAppVersion *repository.InstalledAppVersions, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, error) DeleteDeploymentApp(ctx context.Context, appName string, environmentName string, installAppVersionRequest *appStoreBean.InstallAppVersionDTO) error UpdateInstalledAppAndPipelineStatusForFailedDeploymentStatus(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, triggeredAt time.Time, err error) error - SaveTimelineForACDHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status string, statusDetail string, tx *pg.Tx) error + SaveTimelineForACDHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status string, statusDetail string, statusTime time.Time, tx *pg.Tx) error UpdateChartInfo(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *util.ChartGitAttribute, installedAppVersionHistoryId int, ctx context.Context) error - RefreshAndUpdateACDApp(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *util.ChartGitAttribute, isMonoRepoMigrationRequired bool, ctx context.Context) error + UpdateAndSyncACDApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *util.ChartGitAttribute, isMonoRepoMigrationRequired bool, ctx context.Context, tx *pg.Tx) error } type AppStoreDeploymentArgoCdServiceImpl struct { @@ -78,6 +78,7 @@ type AppStoreDeploymentArgoCdServiceImpl struct { pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository appStoreApplicationVersionRepository appStoreDiscoverRepository.AppStoreApplicationVersionRepository argoClientWrapperService argocdServer.ArgoClientWrapperService + acdConfig *argocdServer.ACDConfig } func NewAppStoreDeploymentArgoCdServiceImpl(logger *zap.SugaredLogger, appStoreDeploymentFullModeService appStoreDeploymentFullMode.AppStoreDeploymentFullModeService, @@ -88,7 +89,8 @@ func NewAppStoreDeploymentArgoCdServiceImpl(logger *zap.SugaredLogger, appStoreD pipelineStatusTimelineService status.PipelineStatusTimelineService, userService user.UserService, pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository, appStoreApplicationVersionRepository appStoreDiscoverRepository.AppStoreApplicationVersionRepository, - argoClientWrapperService argocdServer.ArgoClientWrapperService) *AppStoreDeploymentArgoCdServiceImpl { + argoClientWrapperService argocdServer.ArgoClientWrapperService, acdConfig *argocdServer.ACDConfig, +) *AppStoreDeploymentArgoCdServiceImpl { return &AppStoreDeploymentArgoCdServiceImpl{ Logger: logger, appStoreDeploymentFullModeService: appStoreDeploymentFullModeService, @@ -108,11 +110,12 @@ func NewAppStoreDeploymentArgoCdServiceImpl(logger *zap.SugaredLogger, appStoreD pipelineStatusTimelineRepository: pipelineStatusTimelineRepository, appStoreApplicationVersionRepository: appStoreApplicationVersionRepository, argoClientWrapperService: argoClientWrapperService, + acdConfig: acdConfig, } } -// RefreshAndUpdateACDApp this will update chart info in acd app if required in case of mono repo migration and will refresh argo app -func (impl AppStoreDeploymentArgoCdServiceImpl) RefreshAndUpdateACDApp(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *util.ChartGitAttribute, isMonoRepoMigrationRequired bool, ctx context.Context) error { +// UpdateAndSyncACDApps this will update chart info in acd app if required in case of mono repo migration and will refresh argo app +func (impl AppStoreDeploymentArgoCdServiceImpl) UpdateAndSyncACDApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *util.ChartGitAttribute, isMonoRepoMigrationRequired bool, ctx context.Context, tx *pg.Tx) error { if isMonoRepoMigrationRequired { // update repo details on ArgoCD as repo is changed err := impl.UpdateChartInfo(installAppVersionRequest, ChartGitAttribute, 0, ctx) @@ -121,10 +124,30 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) RefreshAndUpdateACDApp(installAp return err } } - // Doing this to refresh normally by getting app to avoid sync delay argo cd - err := impl.argoClientWrapperService.GetArgoAppWithNormalRefresh(ctx, installAppVersionRequest.ACDAppName) + acdAppName := installAppVersionRequest.ACDAppName + argoApplication, err := impl.acdClient.Get(ctx, &application.ApplicationQuery{Name: &acdAppName}) + if err != nil { + impl.Logger.Errorw("Service err:UpdateAndSyncACDApps - error in acd app by name", "acdAppName", acdAppName, "err", err) + return err + } + + err = impl.argoClientWrapperService.UpdateArgoCDSyncModeIfNeeded(ctx, argoApplication) + if err != nil { + impl.Logger.Errorw("error in updating argocd sync mode", "err", err) + return err + } + syncTime := time.Now() + err = impl.argoClientWrapperService.SyncArgoCDApplicationIfNeededAndRefresh(ctx, acdAppName) if err != nil { impl.Logger.Errorw("error in getting argocd application with normal refresh", "err", err, "argoAppName", installAppVersionRequest.ACDAppName) + return err + } + if !impl.acdConfig.ArgoCDAutoSyncEnabled { + err = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED, "argocd sync completed", syncTime, tx) + if err != nil { + impl.Logger.Errorw("error in saving timeline for acd helm apps", "err", err) + return err + } } return nil } @@ -138,16 +161,17 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) UpdateChartInfo(installAppVersio return nil } -func (impl AppStoreDeploymentArgoCdServiceImpl) SaveTimelineForACDHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status string, statusDetail string, tx *pg.Tx) error { +func (impl AppStoreDeploymentArgoCdServiceImpl) SaveTimelineForACDHelmApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, status string, statusDetail string, statusTime time.Time, tx *pg.Tx) error { if !util.IsAcdApp(installAppVersionRequest.DeploymentAppType) && !util.IsManifestDownload(installAppVersionRequest.DeploymentAppType) { return nil } + timeline := &pipelineConfig.PipelineStatusTimeline{ InstalledAppVersionHistoryId: installAppVersionRequest.InstalledAppVersionHistoryId, Status: status, StatusDetail: statusDetail, - StatusTime: time.Now(), + StatusTime: statusTime, AuditLog: sql.AuditLog{ CreatedBy: installAppVersionRequest.UserId, CreatedOn: time.Now(), @@ -164,7 +188,7 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) SaveTimelineForACDHelmApps(insta func (impl AppStoreDeploymentArgoCdServiceImpl) InstallApp(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, chartGitAttr *util.ChartGitAttribute, ctx context.Context, tx *pg.Tx) (*appStoreBean.InstallAppVersionDTO, error) { - installAppVersionRequest, err := impl.appStoreDeploymentFullModeService.AppStoreDeployOperationACD(installAppVersionRequest, chartGitAttr, ctx) + installAppVersionRequest, err := impl.appStoreDeploymentFullModeService.AppStoreDeployOperationACD(installAppVersionRequest, chartGitAttr, ctx, tx) if err != nil { impl.Logger.Errorw(" error", "err", err) return installAppVersionRequest, err @@ -311,7 +335,7 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) RollbackRelease(ctx context.Cont installedAppVersionHistory.UpdatedOn = time.Now() installedAppVersionHistory.StartedOn = time.Now() installedAppVersionHistory.Status = pipelineConfig.WorkflowInProgress - _, err = impl.installedAppRepositoryHistory.CreateInstalledAppVersionHistory(installedAppVersionHistory, tx) + installedAppVersionHistory, err = impl.installedAppRepositoryHistory.CreateInstalledAppVersionHistory(installedAppVersionHistory, tx) if err != nil { impl.Logger.Errorw("error while fetching from db", "error", err) return installedApp, false, err @@ -319,20 +343,11 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) RollbackRelease(ctx context.Cont installedApp.InstalledAppVersionHistoryId = installedAppVersionHistory.Id //creating deployment started status timeline when mono repo migration is not required - timeline := &pipelineConfig.PipelineStatusTimeline{ - InstalledAppVersionHistoryId: installedApp.InstalledAppVersionHistoryId, - Status: pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_INITIATED, - StatusDetail: "Deployment initiated successfully.", - StatusTime: time.Now(), - AuditLog: sql.AuditLog{ - CreatedBy: installedApp.UserId, - CreatedOn: time.Now(), - UpdatedBy: installedApp.UserId, - UpdatedOn: time.Now(), - }, - } + deploymentInitiatedTimeline := impl.pipelineStatusTimelineService. + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedApp.InstalledAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_INITIATED, "Deployment initiated successfully.", installedApp.UserId, time.Now()) + isAppStore := true - err = impl.pipelineStatusTimelineService.SaveTimeline(timeline, tx, isAppStore) + err = impl.pipelineStatusTimelineService.SaveTimeline(deploymentInitiatedTimeline, tx, isAppStore) if err != nil { impl.Logger.Errorw("error in creating timeline status for deployment initiation for update of installedAppVersionHistoryId", "err", err, "installedAppVersionHistoryId", installedApp.InstalledAppVersionHistoryId) } @@ -340,10 +355,14 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) RollbackRelease(ctx context.Cont if versionHistory.InstalledAppVersionId != activeInstalledAppVersion.Id { err = impl.appStoreDeploymentFullModeService.UpdateRequirementYaml(installedApp, &installedAppVersion.AppStoreApplicationVersion) if err != nil { - impl.Logger.Errorw("error", "err", err) + if errors.Is(err, errors.New(pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED)) { + impl.Logger.Errorw("error", "err", err) + GitCommitFailTimeline := impl.pipelineStatusTimelineService. + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedApp.InstalledAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, "Git commit failed.", installedApp.UserId, time.Now()) + _ = impl.pipelineStatusTimelineService.SaveTimeline(GitCommitFailTimeline, tx, isAppStore) + } return installedApp, false, nil } - activeInstalledAppVersion.Active = false _, err = impl.installedAppRepository.UpdateInstalledAppVersion(activeInstalledAppVersion, nil) if err != nil { @@ -355,8 +374,50 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) RollbackRelease(ctx context.Cont installedApp, err = impl.appStoreDeploymentFullModeService.UpdateValuesYaml(installedApp, tx) if err != nil { impl.Logger.Errorw("error", "err", err) + if errors.Is(err, errors.New(pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED)) { + GitCommitFailTimeline := impl.pipelineStatusTimelineService. + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedApp.InstalledAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, "Git commit failed.", installedApp.UserId, time.Now()) + _ = impl.pipelineStatusTimelineService.SaveTimeline(GitCommitFailTimeline, tx, isAppStore) + } return installedApp, false, nil } + installedAppVersionHistory.GitHash = installedApp.GitHash + _, err = impl.installedAppRepositoryHistory.UpdateInstalledAppVersionHistory(installedAppVersionHistory, tx) + if err != nil { + impl.Logger.Errorw("error in updating installed app version history repository", "err", err) + return installedApp, false, err + } + + isManualSync := !impl.acdConfig.ArgoCDAutoSyncEnabled + + GitCommitSuccessTimeline := impl.pipelineStatusTimelineService. + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedApp.InstalledAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", installedApp.UserId, time.Now()) + timelines := []*pipelineConfig.PipelineStatusTimeline{GitCommitSuccessTimeline} + if isManualSync { + // add ARGOCD_SYNC_INITIATED timeline if manual sync + ArgocdSyncInitiatedTimeline := impl.pipelineStatusTimelineService. + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedApp.InstalledAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED, "ArgoCD sync initiated.", installedApp.UserId, time.Now()) + timelines = append(timelines, ArgocdSyncInitiatedTimeline) + } + err = impl.pipelineStatusTimelineService.SaveTimelines(timelines, tx) + if err != nil { + impl.Logger.Errorw("error in creating timeline status for deployment initiation for update of installedAppVersionHistoryId", "err", err, "installedAppVersionHistoryId", installedApp.InstalledAppVersionHistoryId) + } + + err = impl.argoClientWrapperService.SyncArgoCDApplicationIfNeededAndRefresh(ctx, installedApp.ACDAppName) + if err != nil { + impl.Logger.Errorw("error in getting the argo application with normal refresh", "err", err) + return installedApp, true, nil + } + syncTime := time.Now() + if isManualSync { + ArgocdSyncCompletedTimeline := impl.pipelineStatusTimelineService. + GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedApp.InstalledAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED, "ArgoCD sync completed.", installedApp.UserId, syncTime) + err = impl.pipelineStatusTimelineService.SaveTimeline(ArgocdSyncCompletedTimeline, tx, isAppStore) + if err != nil { + impl.Logger.Errorw("error in creating timeline status for deployment initiation for update of installedAppVersionHistoryId", "err", err, "installedAppVersionHistoryId", installedApp.InstalledAppVersionHistoryId) + } + } //ACD sync operation //impl.appStoreDeploymentFullModeService.SyncACD(installedApp.ACDAppName, ctx) return installedApp, true, nil @@ -520,11 +581,11 @@ func (impl *AppStoreDeploymentArgoCdServiceImpl) OnUpdateRepoInInstalledApp(ctx appStoreGitOpsResponse, err := impl.appStoreDeploymentCommonService.GenerateManifestAndPerformGitOperations(installAppVersionRequest) if err != nil { impl.Logger.Errorw("error in doing gitops operation", "err", err) - _ = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", err), tx) + _ = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", err), time.Now(), tx) } - _ = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", tx) + _ = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", time.Now(), tx) //acd operation register, sync installAppVersionRequest, err = impl.patchAcdApp(ctx, installAppVersionRequest, appStoreGitOpsResponse.ChartGitAttribute) @@ -643,10 +704,10 @@ func (impl AppStoreDeploymentArgoCdServiceImpl) updateValuesYaml(environment *cl gitHash, err := impl.appStoreDeploymentCommonService.CommitConfigToGit(valuesGitConfig) if err != nil { impl.Logger.Errorw("error in git commit", "err", err) - _ = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", err), tx) + _ = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT_FAILED, fmt.Sprintf("Git commit failed - %v", err), time.Now(), tx) return nil, err } - _ = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", tx) + _ = impl.SaveTimelineForACDHelmApps(installAppVersionRequest, pipelineConfig.TIMELINE_STATUS_GIT_COMMIT, "Git commit done successfully.", time.Now(), tx) //update timeline status for git commit state installAppVersionRequest.GitHash = gitHash return installAppVersionRequest, nil diff --git a/pkg/pipeline/CdHandler.go b/pkg/pipeline/CdHandler.go index e20ffe2d33..be01698cff 100644 --- a/pkg/pipeline/CdHandler.go +++ b/pkg/pipeline/CdHandler.go @@ -29,6 +29,7 @@ import ( "github.com/devtron-labs/common-lib/utils/k8s" "github.com/devtron-labs/devtron/api/bean" client "github.com/devtron-labs/devtron/api/helm-app" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/client/argocdServer/application" client2 "github.com/devtron-labs/devtron/client/events" "github.com/devtron-labs/devtron/internal/sql/repository" @@ -83,7 +84,7 @@ type CdHandler interface { CheckArgoAppStatusPeriodicallyAndUpdateInDb(getPipelineDeployedBeforeMinutes int, getPipelineDeployedWithinHours int) error CheckArgoPipelineTimelineStatusPeriodicallyAndUpdateInDb(pendingSinceSeconds int, timeForDegradation int) error UpdatePipelineTimelineAndStatusByLiveApplicationFetch(pipeline *pipelineConfig.Pipeline, installedApp repository3.InstalledApps, userId int32) (err error, isTimelineUpdated bool) - CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipelineId int, userId int32, isAppStoreApplication bool) + CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipelineId int, installedAppVersionId int, userId int32, isAppStoreApplication bool) FetchAppWorkflowStatusForTriggerViewForEnvironment(request resourceGroup2.ResourceGroupingRequest) ([]*pipelineConfig.CdWorkflowStatus, error) FetchAppDeploymentStatusForEnvironments(request resourceGroup2.ResourceGroupingRequest) ([]*pipelineConfig.AppDeploymentStatus, error) DeactivateImageReservationPathsOnFailure(imagePathReservationIds []int) error @@ -126,9 +127,12 @@ type CdHandlerImpl struct { clusterService cluster.ClusterService blobConfigStorageService BlobStorageConfigService customTagService CustomTagService + argocdClientWrapperService argocdServer.ArgoClientWrapperService + AppConfig *app.AppServiceConfig + acdConfig *argocdServer.ACDConfig } -func NewCdHandlerImpl(Logger *zap.SugaredLogger, userService user.UserService, cdWorkflowRepository pipelineConfig.CdWorkflowRepository, ciLogService CiLogService, ciArtifactRepository repository.CiArtifactRepository, ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository, pipelineRepository pipelineConfig.PipelineRepository, envRepository repository2.EnvironmentRepository, ciWorkflowRepository pipelineConfig.CiWorkflowRepository, helmAppService client.HelmAppService, pipelineOverrideRepository chartConfig.PipelineOverrideRepository, workflowDagExecutor WorkflowDagExecutor, appListingService app.AppListingService, appListingRepository repository.AppListingRepository, pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository, application application.ServiceClient, argoUserService argo.ArgoUserService, deploymentEventHandler app.DeploymentEventHandler, eventClient client2.EventClient, pipelineStatusTimelineResourcesService status.PipelineStatusTimelineResourcesService, pipelineStatusSyncDetailService status.PipelineStatusSyncDetailService, pipelineStatusTimelineService status.PipelineStatusTimelineService, appService app.AppService, appStatusService app_status.AppStatusService, enforcerUtil rbac.EnforcerUtil, installedAppRepository repository3.InstalledAppRepository, installedAppVersionHistoryRepository repository3.InstalledAppVersionHistoryRepository, appRepository app2.AppRepository, resourceGroupService resourceGroup2.ResourceGroupService, imageTaggingService ImageTaggingService, k8sUtil *k8s.K8sUtil, workflowService WorkflowService, clusterService cluster.ClusterService, blobConfigStorageService BlobStorageConfigService, customTagService CustomTagService) *CdHandlerImpl { +func NewCdHandlerImpl(Logger *zap.SugaredLogger, userService user.UserService, cdWorkflowRepository pipelineConfig.CdWorkflowRepository, ciLogService CiLogService, ciArtifactRepository repository.CiArtifactRepository, ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository, pipelineRepository pipelineConfig.PipelineRepository, envRepository repository2.EnvironmentRepository, ciWorkflowRepository pipelineConfig.CiWorkflowRepository, helmAppService client.HelmAppService, pipelineOverrideRepository chartConfig.PipelineOverrideRepository, workflowDagExecutor WorkflowDagExecutor, appListingService app.AppListingService, appListingRepository repository.AppListingRepository, pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository, application application.ServiceClient, argoUserService argo.ArgoUserService, deploymentEventHandler app.DeploymentEventHandler, eventClient client2.EventClient, pipelineStatusTimelineResourcesService status.PipelineStatusTimelineResourcesService, pipelineStatusSyncDetailService status.PipelineStatusSyncDetailService, pipelineStatusTimelineService status.PipelineStatusTimelineService, appService app.AppService, appStatusService app_status.AppStatusService, enforcerUtil rbac.EnforcerUtil, installedAppRepository repository3.InstalledAppRepository, installedAppVersionHistoryRepository repository3.InstalledAppVersionHistoryRepository, appRepository app2.AppRepository, resourceGroupService resourceGroup2.ResourceGroupService, imageTaggingService ImageTaggingService, k8sUtil *k8s.K8sUtil, workflowService WorkflowService, clusterService cluster.ClusterService, blobConfigStorageService BlobStorageConfigService, customTagService CustomTagService, argocdClientWrapperService argocdServer.ArgoClientWrapperService, AppConfig *app.AppServiceConfig, acdConfig *argocdServer.ACDConfig) *CdHandlerImpl { cdh := &CdHandlerImpl{ Logger: Logger, userService: userService, @@ -165,6 +169,9 @@ func NewCdHandlerImpl(Logger *zap.SugaredLogger, userService user.UserService, c clusterService: clusterService, blobConfigStorageService: blobConfigStorageService, customTagService: customTagService, + argocdClientWrapperService: argocdClientWrapperService, + AppConfig: AppConfig, + acdConfig: acdConfig, } config, err := types.GetCdConfig() if err != nil { @@ -176,6 +183,7 @@ func NewCdHandlerImpl(Logger *zap.SugaredLogger, userService user.UserService, c type ArgoPipelineStatusSyncEvent struct { PipelineId int `json:"pipelineId"` + InstalledAppVersionId int `json:"installedAppVersionId"` UserId int32 `json:"userId"` IsAppStoreApplication bool `json:"isAppStoreApplication"` } @@ -241,7 +249,7 @@ func (impl *CdHandlerImpl) CheckArgoAppStatusPeriodicallyAndUpdateInDb(getPipeli impl.Logger.Debugw("received stuck argo cd pipelines", "pipelines", pipelines, "number of pipelines", len(pipelines)) for _, pipeline := range pipelines { - impl.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipeline.Id, 1, false) + impl.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipeline.Id, 0, 1, false) } installedAppVersions, err := impl.installedAppRepository.GetArgoPipelinesHavingLatestTriggerStuckInNonTerminalStatusesForAppStore(getPipelineDeployedBeforeMinutes, getPipelineDeployedWithinHours) @@ -252,7 +260,7 @@ func (impl *CdHandlerImpl) CheckArgoAppStatusPeriodicallyAndUpdateInDb(getPipeli impl.Logger.Debugw("received stuck argo installed appStore app", "installedAppVersions", installedAppVersions, "number of triggers", len(installedAppVersions)) for _, installedAppVersion := range installedAppVersions { - impl.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(installedAppVersion.Id, 1, true) + impl.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(0, installedAppVersion.Id, 1, true) } return nil } @@ -275,32 +283,49 @@ func (impl *CdHandlerImpl) CheckArgoPipelineTimelineStatusPeriodicallyAndUpdateI impl.Logger.Debugw("received argo appStore application stuck at kubectl apply synced stage", "pipelines", installedAppVersions) for _, pipeline := range pipelines { - impl.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipeline.Id, 1, false) + impl.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipeline.Id, 0, 1, false) } for _, installedAppVersion := range installedAppVersions { - impl.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(installedAppVersion.Id, 1, true) + impl.CheckAndSendArgoPipelineStatusSyncEventIfNeeded(0, installedAppVersion.Id, 1, true) } return nil } -func (impl *CdHandlerImpl) CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipelineId int, userId int32, isAppStoreApplication bool) { +func (impl *CdHandlerImpl) CheckAndSendArgoPipelineStatusSyncEventIfNeeded(pipelineId int, installedAppVersionId int, userId int32, isAppStoreApplication bool) { var lastSyncTime time.Time var err error if isAppStoreApplication { - lastSyncTime, err = impl.pipelineStatusSyncDetailService.GetLastSyncTimeForLatestInstalledAppVersionHistoryByInstalledAppVersionId(pipelineId) + lastSyncTime, err = impl.pipelineStatusSyncDetailService.GetLastSyncTimeForLatestInstalledAppVersionHistoryByInstalledAppVersionId(installedAppVersionId) } else { lastSyncTime, err = impl.pipelineStatusSyncDetailService.GetLastSyncTimeForLatestCdWfrByCdPipelineId(pipelineId) } if err != nil { - impl.Logger.Errorw("error in getting last sync time by pipelineId", "err", err, "pipelineId", pipelineId) + impl.Logger.Errorw("error in getting last sync time by pipelineId", "err", err, "pipelineId", pipelineId, "installedAppVersionHistoryId", installedAppVersionId) return } - //TODO: remove hard coding + + // sync argocd app + if pipelineId != 0 { + err := impl.syncACDDevtronApps(impl.AppConfig.ArgocdManualSyncCronPipelineDeployedBefore, pipelineId) + if err != nil { + impl.Logger.Errorw("error in syncing devtron apps deployed via argoCD", "err", err) + return + } + } + if installedAppVersionId != 0 { + err := impl.SyncACDHelmApps(impl.AppConfig.ArgocdManualSyncCronPipelineDeployedBefore, installedAppVersionId) + if err != nil { + impl.Logger.Errorw("error in syncing Helm apps deployed via argoCD", "err", err) + return + } + } + //pipelineId can be cdPipelineId or installedAppVersionId, using isAppStoreApplication flag to identify between them if lastSyncTime.IsZero() || (!lastSyncTime.IsZero() && time.Since(lastSyncTime) > 5*time.Second) { //create new nats event statusUpdateEvent := ArgoPipelineStatusSyncEvent{ PipelineId: pipelineId, + InstalledAppVersionId: installedAppVersionId, UserId: userId, IsAppStoreApplication: isAppStoreApplication, } @@ -328,6 +353,14 @@ func (impl *CdHandlerImpl) UpdatePipelineTimelineAndStatusByLiveApplicationFetch //drop event return nil, isTimelineUpdated } + + if !impl.acdConfig.ArgoCDAutoSyncEnabled { + // if manual sync check for application sync status + isArgoAppSynced := impl.pipelineStatusTimelineService.GetArgoAppSyncStatus(cdWfr.Id) + if !isArgoAppSynced { + return nil, isTimelineUpdated + } + } //this should only be called when we have git-ops configured //try fetching status from argo cd acdToken, err := impl.argoUserService.GetLatestDevtronArgoCdUserToken() @@ -405,12 +438,17 @@ func (impl *CdHandlerImpl) UpdatePipelineTimelineAndStatusByLiveApplicationFetch //drop event return nil, isTimelineUpdated } + if !impl.acdConfig.ArgoCDAutoSyncEnabled { + isArgoAppSynced := impl.pipelineStatusTimelineService.GetArgoAppSyncStatusForAppStore(installedAppVersionHistory.Id) + if !isArgoAppSynced { + return nil, isTimelineUpdated + } + } appDetails, err := impl.appRepository.FindActiveById(installedApp.AppId) if err != nil { impl.Logger.Errorw("error in getting appDetails from appId", "err", err) return nil, isTimelineUpdated } - //TODO if Environment object in installedApp is nil then fetch envDetails also from envRepository envDetail, err := impl.envRepository.FindById(installedApp.EnvironmentId) if err != nil { @@ -1608,3 +1646,137 @@ func (impl *CdHandlerImpl) FetchAppDeploymentStatusForEnvironments(request resou func (impl *CdHandlerImpl) DeactivateImageReservationPathsOnFailure(imagePathReservationIds []int) error { return impl.customTagService.DeactivateImagePathReservationByImageIds(imagePathReservationIds) } + +func (impl *CdHandlerImpl) syncACDDevtronApps(deployedBeforeMinutes int, pipelineId int) error { + if impl.acdConfig.ArgoCDAutoSyncEnabled { + // don't check for apps if auto sync is enabled + return nil + } + cdWfr, err := impl.cdWorkflowRepository.FindLastStatusByPipelineIdAndRunnerType(pipelineId, bean.CD_WORKFLOW_TYPE_DEPLOY) + if err != nil { + impl.Logger.Errorw("error in getting latest cdWfr by cdPipelineId", "err", err, "pipelineId", pipelineId) + return err + } + if util3.IsTerminalStatus(cdWfr.Status) { + return nil + } + pipelineStatusTimeline, err := impl.pipelineStatusTimelineRepository.FetchLatestTimelineByWfrId(cdWfr.Id) + if err != nil { + impl.Logger.Errorw("error in fetching latest pipeline status by cdWfrId", "err", err) + return err + } + if pipelineStatusTimeline.Status == pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED && time.Since(pipelineStatusTimeline.StatusTime) >= time.Minute*time.Duration(deployedBeforeMinutes) { + acdToken, err := impl.argoUserService.GetLatestDevtronArgoCdUserToken() + if err != nil { + impl.Logger.Errorw("error in getting acd token", "err", err) + return err + } + ctx := context.Background() + ctx = context.WithValue(ctx, "token", acdToken) + syncTime := time.Now() + syncErr := impl.argocdClientWrapperService.SyncArgoCDApplicationIfNeededAndRefresh(ctx, cdWfr.CdWorkflow.Pipeline.DeploymentAppName) + if syncErr != nil { + impl.Logger.Errorw("error in syncing argoCD app", "err", syncErr) + timelineObject := impl.pipelineStatusTimelineService.GetTimelineDbObjectByTimelineStatusAndTimelineDescription(cdWfr.Id, 0, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_FAILED, fmt.Sprintf("error occured in syncing argocd application. err: %s", syncErr.Error()), 1, time.Now()) + _ = impl.pipelineStatusTimelineService.SaveTimeline(timelineObject, nil, false) + cdWfr.Status = pipelineConfig.WorkflowFailed + cdWfr.UpdatedBy = 1 + cdWfr.UpdatedOn = time.Now() + cdWfrUpdateErr := impl.cdWorkflowRepository.UpdateWorkFlowRunner(&cdWfr) + if cdWfrUpdateErr != nil { + impl.Logger.Errorw("error in updating cd workflow runner as failed in argocd app sync cron", "err", err) + return err + } + return nil + } + timeline := &pipelineConfig.PipelineStatusTimeline{ + CdWorkflowRunnerId: cdWfr.Id, + StatusTime: syncTime, + Status: pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED, + StatusDetail: "argocd sync completed", + AuditLog: sql.AuditLog{ + CreatedBy: 1, + CreatedOn: time.Now(), + UpdatedBy: 1, + UpdatedOn: time.Now(), + }, + } + _, err, _ = impl.pipelineStatusTimelineService.SavePipelineStatusTimelineIfNotAlreadyPresent(timeline.CdWorkflowRunnerId, timeline.Status, timeline, false) + } + return nil +} + +func (impl *CdHandlerImpl) SyncACDHelmApps(deployedBeforeMinutes int, installedAppVersionId int) error { + if impl.acdConfig.ArgoCDAutoSyncEnabled { + // don't check for apps if auto sync is enabled + return nil + } + installedAppVersionHistory, err := impl.installedAppVersionHistoryRepository.GetLatestInstalledAppVersionHistory(installedAppVersionId) + if err != nil { + impl.Logger.Errorw("error in getting latest cdWfr by cdPipelineId", "err", err, "installedAppVersionId", installedAppVersionId) + return err + } + if util3.IsTerminalStatus(installedAppVersionHistory.Status) { + return nil + } + installedAppVersionHistoryId := installedAppVersionHistory.Id + pipelineStatusTimeline, err := impl.pipelineStatusTimelineRepository.FetchLatestTimelinesByInstalledAppVersionHistoryId(installedAppVersionHistoryId) + if err != nil { + impl.Logger.Errorw("error in fetching latest pipeline status by cdWfrId", "err", err) + return err + } + if pipelineStatusTimeline.Status == pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_INITIATED && time.Since(pipelineStatusTimeline.StatusTime) >= time.Minute*time.Duration(deployedBeforeMinutes) { + installedApp, err := impl.installedAppRepository.GetInstalledAppByInstalledAppVersionId(installedAppVersionHistory.InstalledAppVersionId) + if err != nil { + impl.Logger.Errorw("error in fetching installed_app by installedAppVersionId", "err", err) + return err + } + appDetails, err := impl.appRepository.FindActiveById(installedApp.AppId) + if err != nil { + impl.Logger.Errorw("error in getting appDetails from appId", "err", err) + return err + } + envDetails, err := impl.envRepository.FindById(installedApp.EnvironmentId) + if err != nil { + impl.Logger.Errorw("error in fetching environment by envId", "err", err) + } + argoAppName := fmt.Sprintf("%s-%s", appDetails.AppName, envDetails.Name) + acdToken, err := impl.argoUserService.GetLatestDevtronArgoCdUserToken() + if err != nil { + impl.Logger.Errorw("error in getting acd token", "err", err) + return err + } + ctx := context.Background() + ctx = context.WithValue(ctx, "token", acdToken) + syncTime := time.Now() + syncErr := impl.argocdClientWrapperService.SyncArgoCDApplicationIfNeededAndRefresh(ctx, argoAppName) + if syncErr != nil { + impl.Logger.Errorw("error in syncing argoCD app", "err", syncErr) + timelineObject := impl.pipelineStatusTimelineService.GetTimelineDbObjectByTimelineStatusAndTimelineDescription(0, installedAppVersionHistoryId, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_FAILED, fmt.Sprintf("error occured in syncing argocd application. err: %s", syncErr.Error()), 1, time.Now()) + _ = impl.pipelineStatusTimelineService.SaveTimeline(timelineObject, nil, false) + installedAppVersionHistory.Status = pipelineConfig.WorkflowFailed + installedAppVersionHistory.UpdatedBy = 1 + installedAppVersionHistory.UpdatedOn = time.Now() + _, installedAppUpdateErr := impl.installedAppVersionHistoryRepository.UpdateInstalledAppVersionHistory(installedAppVersionHistory, nil) + if installedAppUpdateErr != nil { + impl.Logger.Errorw("error in updating cd workflow runner as failed in argocd app sync cron", "err", err) + return err + } + return nil + } + timeline := &pipelineConfig.PipelineStatusTimeline{ + InstalledAppVersionHistoryId: installedAppVersionHistoryId, + StatusTime: syncTime, + Status: pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED, + StatusDetail: "argocd sync completed", + AuditLog: sql.AuditLog{ + CreatedBy: 1, + CreatedOn: time.Now(), + UpdatedBy: 1, + UpdatedOn: time.Now(), + }, + } + _, err, _ = impl.pipelineStatusTimelineService.SavePipelineStatusTimelineIfNotAlreadyPresent(timeline.CdWorkflowRunnerId, timeline.Status, timeline, false) + } + return nil +} diff --git a/pkg/pipeline/WorkflowDagExecutor.go b/pkg/pipeline/WorkflowDagExecutor.go index 6ecb384870..d8fa8d3b1b 100644 --- a/pkg/pipeline/WorkflowDagExecutor.go +++ b/pkg/pipeline/WorkflowDagExecutor.go @@ -197,6 +197,7 @@ type WorkflowDagExecutorImpl struct { argoClientWrapperService argocdServer.ArgoClientWrapperService pipelineConfigListenerService PipelineConfigListenerService customTagService CustomTagService + ACDConfig *argocdServer.ACDConfig } const kedaAutoscaling = "kedaAutoscaling" @@ -218,6 +219,8 @@ const ( CHILD_CD_CLUSTER_NAME_PREFIX = "CHILD_CD_CLUSTER_NAME" CHILD_CD_COUNT = "CHILD_CD_COUNT" DEVTRON_SYSTEM_USER_ID = 1 + ARGOCD_SYNC_ERROR = "error in syncing argoCD app" + ARGOCD_REFRESH_ERROR = "Error in refreshing argocd app" ) type DevtronAppReleaseContextType struct { @@ -302,6 +305,7 @@ func NewWorkflowDagExecutorImpl(Logger *zap.SugaredLogger, pipelineRepository pi argoClientWrapperService argocdServer.ArgoClientWrapperService, pipelineConfigListenerService PipelineConfigListenerService, customTagService CustomTagService, + ACDConfig *argocdServer.ACDConfig, ) *WorkflowDagExecutorImpl { wde := &WorkflowDagExecutorImpl{logger: Logger, pipelineRepository: pipelineRepository, @@ -378,6 +382,7 @@ func NewWorkflowDagExecutorImpl(Logger *zap.SugaredLogger, pipelineRepository pi argoClientWrapperService: argoClientWrapperService, pipelineConfigListenerService: pipelineConfigListenerService, customTagService: customTagService, + ACDConfig: ACDConfig, } config, err := types.GetCdConfig() if err != nil { @@ -2381,7 +2386,7 @@ func (impl *WorkflowDagExecutorImpl) ManualCdTrigger(overrideRequest *bean.Value } overrideRequest.CdWorkflowId = cdWorkflowId // creating cd pipeline status timeline for deployment initialisation - timeline := impl.pipelineStatusTimelineService.GetTimelineDbObjectByTimelineStatusAndTimelineDescription(savedWfr.Id, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_INITIATED, pipelineConfig.TIMELINE_DESCRIPTION_DEPLOYMENT_INITIATED, overrideRequest.UserId) + timeline := impl.pipelineStatusTimelineService.GetTimelineDbObjectByTimelineStatusAndTimelineDescription(savedWfr.Id, 0, pipelineConfig.TIMELINE_STATUS_DEPLOYMENT_INITIATED, pipelineConfig.TIMELINE_DESCRIPTION_DEPLOYMENT_INITIATED, overrideRequest.UserId, time.Now()) _, span = otel.Tracer("orchestrator").Start(ctx, "cdPipelineStatusTimelineRepo.SaveTimelineForACDHelmApps") err = impl.pipelineStatusTimelineService.SaveTimeline(timeline, nil, false) @@ -2949,6 +2954,12 @@ func (impl *WorkflowDagExecutorImpl) TriggerPipeline(overrideRequest *bean.Value } if triggerEvent.PerformChartPush { + //update workflow runner status, used in app workflow view + err = impl.UpdateCDWorkflowRunnerStatus(ctx, overrideRequest, triggerEvent.TriggerdAt, pipelineConfig.WorkflowInProgress, "") + if err != nil { + impl.logger.Errorw("error in updating the workflow runner status, createHelmAppForCdPipeline", "err", err) + return releaseNo, manifest, err + } manifestPushTemplate, err := impl.BuildManifestPushTemplate(overrideRequest, valuesOverrideResponse, builtChartPath, &manifest) if err != nil { impl.logger.Errorw("error in building manifest push template", "err", err) @@ -3409,23 +3420,41 @@ func (impl *WorkflowDagExecutorImpl) DeployArgocdApp(overrideRequest *bean.Value impl.logger.Debugw("argocd application created", "name", name) _, span = otel.Tracer("orchestrator").Start(ctx, "updateArgoPipeline") - updateAppInArgocd, err := impl.updateArgoPipeline(overrideRequest.AppId, valuesOverrideResponse.Pipeline.Name, valuesOverrideResponse.EnvOverride, ctx) + updateAppInArgocd, err := impl.updateArgoPipeline(valuesOverrideResponse.Pipeline, valuesOverrideResponse.EnvOverride, ctx) span.End() if err != nil { impl.logger.Errorw("error in updating argocd app ", "err", err) return err } + syncTime := time.Now() + err = impl.argoClientWrapperService.SyncArgoCDApplicationIfNeededAndRefresh(ctx, valuesOverrideResponse.Pipeline.DeploymentAppName) + if err != nil { + impl.logger.Errorw("error in getting argo application with normal refresh", "argoAppName", valuesOverrideResponse.Pipeline.DeploymentAppName) + return fmt.Errorf("%s. err: %s", ARGOCD_SYNC_ERROR, err.Error()) + } + if !impl.ACDConfig.ArgoCDAutoSyncEnabled { + timeline := &pipelineConfig.PipelineStatusTimeline{ + CdWorkflowRunnerId: overrideRequest.WfrId, + StatusTime: syncTime, + AuditLog: sql.AuditLog{ + CreatedBy: 1, + CreatedOn: time.Now(), + UpdatedBy: 1, + UpdatedOn: time.Now(), + }, + Status: pipelineConfig.TIMELINE_STATUS_ARGOCD_SYNC_COMPLETED, + StatusDetail: "argocd sync completed", + } + _, err, _ = impl.pipelineStatusTimelineService.SavePipelineStatusTimelineIfNotAlreadyPresent(overrideRequest.WfrId, timeline.Status, timeline, false) + if err != nil { + impl.logger.Errorw("error in saving pipeline status timeline", "err", err) + } + } if updateAppInArgocd { impl.logger.Debug("argo-cd successfully updated") } else { impl.logger.Debug("argo-cd failed to update, ignoring it") } - //update workflow runner status, used in app workflow view - err = impl.UpdateCDWorkflowRunnerStatus(ctx, overrideRequest, triggeredAt, pipelineConfig.WorkflowInProgress, "") - if err != nil { - impl.logger.Errorw("error in updating the workflow runner status, createHelmAppForCdPipeline", "err", err) - return err - } return nil } @@ -3450,6 +3479,7 @@ func (impl *WorkflowDagExecutorImpl) createArgoApplicationIfRequired(appId int, appNamespace = "default" } namespace := argocdServer.DevtronInstalationNs + appRequest := &argocdServer.AppTemplate{ ApplicationName: argoAppName, Namespace: namespace, @@ -3459,9 +3489,9 @@ func (impl *WorkflowDagExecutorImpl) createArgoApplicationIfRequired(appId int, ValuesFile: impl.getValuesFileForEnv(envModel.Id), RepoPath: chart.ChartLocation, RepoUrl: chart.GitRepoUrl, + AutoSyncEnabled: impl.ACDConfig.ArgoCDAutoSyncEnabled, } - - argoAppName, err := impl.argoK8sClient.CreateAcdApp(appRequest, envModel.Cluster) + argoAppName, err := impl.argoK8sClient.CreateAcdApp(appRequest, envModel.Cluster, argocdServer.ARGOCD_APPLICATION_TEMPLATE) if err != nil { return "", err } @@ -4392,33 +4422,23 @@ func (impl *WorkflowDagExecutorImpl) autoscalingCheckBeforeTrigger(ctx context.C return merged } -func (impl *WorkflowDagExecutorImpl) updateArgoPipeline(appId int, pipelineName string, envOverride *chartConfig.EnvConfigOverride, ctx context.Context) (bool, error) { - //repo has been registered while helm create +// update repoUrl, revision and argo app sync mode (auto/manual) if needed +func (impl *WorkflowDagExecutorImpl) updateArgoPipeline(pipeline *pipelineConfig.Pipeline, envOverride *chartConfig.EnvConfigOverride, ctx context.Context) (bool, error) { if ctx == nil { - impl.logger.Errorw("err in syncing ACD, ctx is NULL", "pipelineName", pipelineName) + impl.logger.Errorw("err in syncing ACD, ctx is NULL", "pipelineName", pipeline.Name) return false, nil } - app, err := impl.appRepository.FindById(appId) - if err != nil { - impl.logger.Errorw("no app found ", "err", err) - return false, err - } - envModel, err := impl.envRepository.FindById(envOverride.TargetEnvironment) - if err != nil { - return false, err - } - argoAppName := fmt.Sprintf("%s-%s", app.AppName, envModel.Name) - impl.logger.Infow("received payload, updateArgoPipeline", "appId", appId, "pipelineName", pipelineName, "envId", envOverride.TargetEnvironment, "argoAppName", argoAppName, "context", ctx) + argoAppName := pipeline.DeploymentAppName + impl.logger.Infow("received payload, updateArgoPipeline", "appId", pipeline.AppId, "pipelineName", pipeline.Name, "envId", envOverride.TargetEnvironment, "argoAppName", argoAppName, "context", ctx) argoApplication, err := impl.acdClient.Get(ctx, &application3.ApplicationQuery{Name: &argoAppName}) if err != nil { - impl.logger.Errorw("no argo app exists", "app", argoAppName, "pipeline", pipelineName) + impl.logger.Errorw("no argo app exists", "app", argoAppName, "pipeline", pipeline.Name) return false, err } //if status, ok:=status.FromError(err);ok{ appStatus, _ := status2.FromError(err) - if appStatus.Code() == codes.OK { - impl.logger.Debugw("argo app exists", "app", argoAppName, "pipeline", pipelineName) + impl.logger.Debugw("argo app exists", "app", argoAppName, "pipeline", pipeline.Name) if argoApplication.Spec.Source.Path != envOverride.Chart.ChartLocation || argoApplication.Spec.Source.TargetRevision != "master" { patchReq := v1alpha1.Application{Spec: v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{Path: envOverride.Chart.ChartLocation, RepoURL: envOverride.Chart.GitRepoUrl, TargetRevision: "master"}}} reqbyte, err := json.Marshal(patchReq) @@ -4429,24 +4449,24 @@ func (impl *WorkflowDagExecutorImpl) updateArgoPipeline(appId int, pipelineName patchType := "merge" _, err = impl.acdClient.Patch(ctx, &application3.ApplicationPatchRequest{Patch: &reqString, Name: &argoAppName, PatchType: &patchType}) if err != nil { - impl.logger.Errorw("error in creating argo pipeline ", "name", pipelineName, "patch", string(reqbyte), "err", err) + impl.logger.Errorw("error in creating argo pipeline ", "name", pipeline.Name, "patch", string(reqbyte), "err", err) return false, err } impl.logger.Debugw("pipeline update req ", "res", patchReq) } else { impl.logger.Debug("pipeline no need to update ") } - // Doing normal refresh to avoid the sync delay in argo-cd. - err2 := impl.argoClientWrapperService.GetArgoAppWithNormalRefresh(ctx, argoAppName) - if err2 != nil { - impl.logger.Errorw("error in getting argo application with normal refresh", "argoAppName", argoAppName, "pipelineName", pipelineName) + err := impl.argoClientWrapperService.UpdateArgoCDSyncModeIfNeeded(ctx, argoApplication) + if err != nil { + impl.logger.Errorw("error in updating argocd sync mode", "err", err) + return false, err } return true, nil } else if appStatus.Code() == codes.NotFound { - impl.logger.Errorw("argo app not found", "app", argoAppName, "pipeline", pipelineName) + impl.logger.Errorw("argo app not found", "app", argoAppName, "pipeline", pipeline.Name) return false, nil } else { - impl.logger.Errorw("err in checking application on gocd", "err", err, "pipeline", pipelineName) + impl.logger.Errorw("err in checking application on argoCD", "err", err, "pipeline", pipeline.Name) return false, err } } diff --git a/scripts/argo-assets/APPLICATION_TEMPLATE.JSON b/scripts/argo-assets/APPLICATION_TEMPLATE.tmpl similarity index 92% rename from scripts/argo-assets/APPLICATION_TEMPLATE.JSON rename to scripts/argo-assets/APPLICATION_TEMPLATE.tmpl index 01e27a8573..3d3237a008 100644 --- a/scripts/argo-assets/APPLICATION_TEMPLATE.JSON +++ b/scripts/argo-assets/APPLICATION_TEMPLATE.tmpl @@ -23,9 +23,9 @@ "targetRevision": "master" }, "syncPolicy": { - "automated": { + {{if .AutoSyncEnabled }}"automated": { "prune": true - }, + }, {{end}} "retry": { "backoff": { "duration": "5s", @@ -37,5 +37,3 @@ } } } - - diff --git a/wire_gen.go b/wire_gen.go index 6d77689ce6..9700eb8fd0 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -411,18 +411,22 @@ func InitializeApp() (*App, error) { appStoreDeploymentCommonServiceImpl := appStoreDeploymentCommon.NewAppStoreDeploymentCommonServiceImpl(sugaredLogger, installedAppRepositoryImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, chartTemplateServiceImpl, refChartProxyDir, gitFactory, gitOpsConfigRepositoryImpl) ociRegistryConfigRepositoryImpl := repository5.NewOCIRegistryConfigRepositoryImpl(db) appStoreDeploymentHelmServiceImpl := appStoreDeploymentTool.NewAppStoreDeploymentHelmServiceImpl(sugaredLogger, helmAppServiceImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, helmAppClientImpl, installedAppRepositoryImpl, appStoreDeploymentCommonServiceImpl, ociRegistryConfigRepositoryImpl) - argoClientWrapperServiceImpl := argocdServer.NewArgoClientWrapperServiceImpl(sugaredLogger, applicationServiceClientImpl) - appStoreDeploymentFullModeServiceImpl := appStoreDeploymentFullMode.NewAppStoreDeploymentFullModeServiceImpl(sugaredLogger, chartTemplateServiceImpl, refChartProxyDir, repositoryServiceClientImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, applicationServiceClientImpl, argoK8sClientImpl, gitFactory, acdAuthConfig, globalEnvVariables, installedAppRepositoryImpl, tokenCache, argoUserServiceImpl, gitOpsConfigRepositoryImpl, pipelineStatusTimelineServiceImpl, appStoreDeploymentCommonServiceImpl, argoClientWrapperServiceImpl, pubSubClientServiceImpl, installedAppVersionHistoryRepositoryImpl) - appStoreDeploymentArgoCdServiceImpl := appStoreDeploymentGitopsTool.NewAppStoreDeploymentArgoCdServiceImpl(sugaredLogger, appStoreDeploymentFullModeServiceImpl, applicationServiceClientImpl, chartGroupDeploymentRepositoryImpl, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, chartTemplateServiceImpl, gitFactory, argoUserServiceImpl, appStoreDeploymentCommonServiceImpl, helmAppServiceImpl, gitOpsConfigRepositoryImpl, appStatusServiceImpl, pipelineStatusTimelineServiceImpl, userServiceImpl, pipelineStatusTimelineRepositoryImpl, appStoreApplicationVersionRepositoryImpl, argoClientWrapperServiceImpl) + acdConfig, err := argocdServer.GetACDDeploymentConfig() + if err != nil { + return nil, err + } + argoClientWrapperServiceImpl := argocdServer.NewArgoClientWrapperServiceImpl(sugaredLogger, applicationServiceClientImpl, acdConfig) + appStoreDeploymentFullModeServiceImpl := appStoreDeploymentFullMode.NewAppStoreDeploymentFullModeServiceImpl(sugaredLogger, chartTemplateServiceImpl, refChartProxyDir, repositoryServiceClientImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, applicationServiceClientImpl, argoK8sClientImpl, gitFactory, acdAuthConfig, globalEnvVariables, installedAppRepositoryImpl, tokenCache, argoUserServiceImpl, gitOpsConfigRepositoryImpl, pipelineStatusTimelineServiceImpl, appStoreDeploymentCommonServiceImpl, argoClientWrapperServiceImpl, pubSubClientServiceImpl, installedAppVersionHistoryRepositoryImpl, acdConfig) + appStoreDeploymentArgoCdServiceImpl := appStoreDeploymentGitopsTool.NewAppStoreDeploymentArgoCdServiceImpl(sugaredLogger, appStoreDeploymentFullModeServiceImpl, applicationServiceClientImpl, chartGroupDeploymentRepositoryImpl, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, chartTemplateServiceImpl, gitFactory, argoUserServiceImpl, appStoreDeploymentCommonServiceImpl, helmAppServiceImpl, gitOpsConfigRepositoryImpl, appStatusServiceImpl, pipelineStatusTimelineServiceImpl, userServiceImpl, pipelineStatusTimelineRepositoryImpl, appStoreApplicationVersionRepositoryImpl, argoClientWrapperServiceImpl, acdConfig) deploymentServiceTypeConfig, err := service.GetDeploymentServiceTypeConfig() if err != nil { return nil, err } - appStoreDeploymentServiceImpl := service.NewAppStoreDeploymentServiceImpl(sugaredLogger, installedAppRepositoryImpl, chartGroupDeploymentRepositoryImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, clusterInstalledAppsRepositoryImpl, appRepositoryImpl, appStoreDeploymentHelmServiceImpl, appStoreDeploymentArgoCdServiceImpl, environmentServiceImpl, clusterServiceImplExtended, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, globalEnvVariables, installedAppVersionHistoryRepositoryImpl, gitOpsConfigRepositoryImpl, attributesServiceImpl, deploymentServiceTypeConfig, chartTemplateServiceImpl) + appStoreDeploymentServiceImpl := service.NewAppStoreDeploymentServiceImpl(sugaredLogger, installedAppRepositoryImpl, chartGroupDeploymentRepositoryImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, clusterInstalledAppsRepositoryImpl, appRepositoryImpl, appStoreDeploymentHelmServiceImpl, appStoreDeploymentArgoCdServiceImpl, environmentServiceImpl, clusterServiceImplExtended, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, globalEnvVariables, installedAppVersionHistoryRepositoryImpl, gitOpsConfigRepositoryImpl, attributesServiceImpl, deploymentServiceTypeConfig, chartTemplateServiceImpl, acdConfig) k8sCommonServiceImpl := k8s2.NewK8sCommonServiceImpl(sugaredLogger, k8sUtil, clusterServiceImplExtended) manifestPushConfigRepositoryImpl := repository11.NewManifestPushConfigRepository(sugaredLogger, db) - gitOpsManifestPushServiceImpl := app2.NewGitOpsManifestPushServiceImpl(sugaredLogger, chartTemplateServiceImpl, chartServiceImpl, gitOpsConfigRepositoryImpl, gitFactory, pipelineStatusTimelineServiceImpl) - appServiceImpl := app2.NewAppService(envConfigOverrideRepositoryImpl, pipelineOverrideRepositoryImpl, mergeUtil, sugaredLogger, ciArtifactRepositoryImpl, pipelineRepositoryImpl, dbMigrationConfigRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, applicationServiceClientImpl, tokenCache, acdAuthConfig, enforcerImpl, enforcerUtilImpl, userServiceImpl, appListingRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineConfigRepositoryImpl, configMapRepositoryImpl, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, chartRepositoryImpl, ciPipelineMaterialRepositoryImpl, cdWorkflowRepositoryImpl, commonServiceImpl, imageScanDeployInfoRepositoryImpl, imageScanHistoryRepositoryImpl, argoK8sClientImpl, gitFactory, pipelineStrategyHistoryServiceImpl, configMapHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, chartTemplateServiceImpl, refChartDir, chartRefRepositoryImpl, chartServiceImpl, helmAppClientImpl, argoUserServiceImpl, pipelineStatusTimelineRepositoryImpl, appCrudOperationServiceImpl, configMapHistoryRepositoryImpl, pipelineStrategyHistoryRepositoryImpl, deploymentTemplateHistoryRepositoryImpl, dockerRegistryIpsConfigServiceImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceConfig, gitOpsConfigRepositoryImpl, appStatusServiceImpl, installedAppRepositoryImpl, appStoreDeploymentServiceImpl, k8sCommonServiceImpl, installedAppVersionHistoryRepositoryImpl, globalEnvVariables, helmAppServiceImpl, manifestPushConfigRepositoryImpl, gitOpsManifestPushServiceImpl, argoClientWrapperServiceImpl, scopedVariableCMCSManagerImpl) + gitOpsManifestPushServiceImpl := app2.NewGitOpsManifestPushServiceImpl(sugaredLogger, chartTemplateServiceImpl, chartServiceImpl, gitOpsConfigRepositoryImpl, gitFactory, pipelineStatusTimelineServiceImpl, pipelineStatusTimelineRepositoryImpl, acdConfig) + appServiceImpl := app2.NewAppService(envConfigOverrideRepositoryImpl, pipelineOverrideRepositoryImpl, mergeUtil, sugaredLogger, ciArtifactRepositoryImpl, pipelineRepositoryImpl, dbMigrationConfigRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, applicationServiceClientImpl, tokenCache, acdAuthConfig, enforcerImpl, enforcerUtilImpl, userServiceImpl, appListingRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineConfigRepositoryImpl, configMapRepositoryImpl, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, chartRepositoryImpl, ciPipelineMaterialRepositoryImpl, cdWorkflowRepositoryImpl, commonServiceImpl, imageScanDeployInfoRepositoryImpl, imageScanHistoryRepositoryImpl, argoK8sClientImpl, gitFactory, pipelineStrategyHistoryServiceImpl, configMapHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, chartTemplateServiceImpl, refChartDir, chartRefRepositoryImpl, chartServiceImpl, helmAppClientImpl, argoUserServiceImpl, pipelineStatusTimelineRepositoryImpl, appCrudOperationServiceImpl, configMapHistoryRepositoryImpl, pipelineStrategyHistoryRepositoryImpl, deploymentTemplateHistoryRepositoryImpl, dockerRegistryIpsConfigServiceImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceConfig, gitOpsConfigRepositoryImpl, appStatusServiceImpl, installedAppRepositoryImpl, appStoreDeploymentServiceImpl, k8sCommonServiceImpl, installedAppVersionHistoryRepositoryImpl, globalEnvVariables, helmAppServiceImpl, manifestPushConfigRepositoryImpl, gitOpsManifestPushServiceImpl, argoClientWrapperServiceImpl, scopedVariableCMCSManagerImpl, acdConfig) validate, err := util.IntValidator() if err != nil { return nil, err @@ -463,7 +467,7 @@ func InitializeApp() (*App, error) { customTagServiceImpl := pipeline.NewCustomTagService(sugaredLogger, imageTagRepositoryImpl) pluginInputVariableParserImpl := pipeline.NewPluginInputVariableParserImpl(sugaredLogger, dockerRegistryConfigImpl, customTagServiceImpl) pipelineConfigListenerServiceImpl := pipeline.NewPipelineConfigListenerServiceImpl(sugaredLogger) - workflowDagExecutorImpl := pipeline.NewWorkflowDagExecutorImpl(sugaredLogger, pipelineRepositoryImpl, cdWorkflowRepositoryImpl, pubSubClientServiceImpl, appServiceImpl, workflowServiceImpl, ciArtifactRepositoryImpl, ciPipelineRepositoryImpl, materialRepositoryImpl, pipelineOverrideRepositoryImpl, userServiceImpl, deploymentGroupRepositoryImpl, environmentRepositoryImpl, enforcerImpl, enforcerUtilImpl, tokenCache, acdAuthConfig, eventSimpleFactoryImpl, eventRESTClientImpl, cvePolicyRepositoryImpl, imageScanResultRepositoryImpl, appWorkflowRepositoryImpl, prePostCdScriptHistoryServiceImpl, argoUserServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineStatusTimelineServiceImpl, ciTemplateRepositoryImpl, ciWorkflowRepositoryImpl, appLabelRepositoryImpl, clientImpl, pipelineStageServiceImpl, k8sCommonServiceImpl, variableSnapshotHistoryServiceImpl, globalPluginServiceImpl, pluginInputVariableParserImpl, scopedVariableCMCSManagerImpl, deploymentTemplateHistoryServiceImpl, configMapHistoryServiceImpl, pipelineStrategyHistoryServiceImpl, manifestPushConfigRepositoryImpl, gitOpsManifestPushServiceImpl, ciPipelineMaterialRepositoryImpl, imageScanHistoryRepositoryImpl, imageScanDeployInfoRepositoryImpl, appCrudOperationServiceImpl, pipelineConfigRepositoryImpl, dockerRegistryIpsConfigServiceImpl, chartRepositoryImpl, chartTemplateServiceImpl, pipelineStrategyHistoryRepositoryImpl, appRepositoryImpl, deploymentTemplateHistoryRepositoryImpl, argoK8sClientImpl, configMapRepositoryImpl, configMapHistoryRepositoryImpl, refChartDir, helmAppServiceImpl, helmAppClientImpl, chartRefRepositoryImpl, envConfigOverrideRepositoryImpl, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, dbMigrationConfigRepositoryImpl, mergeUtil, gitOpsConfigRepositoryImpl, gitFactory, applicationServiceClientImpl, argoClientWrapperServiceImpl, pipelineConfigListenerServiceImpl, customTagServiceImpl) + workflowDagExecutorImpl := pipeline.NewWorkflowDagExecutorImpl(sugaredLogger, pipelineRepositoryImpl, cdWorkflowRepositoryImpl, pubSubClientServiceImpl, appServiceImpl, workflowServiceImpl, ciArtifactRepositoryImpl, ciPipelineRepositoryImpl, materialRepositoryImpl, pipelineOverrideRepositoryImpl, userServiceImpl, deploymentGroupRepositoryImpl, environmentRepositoryImpl, enforcerImpl, enforcerUtilImpl, tokenCache, acdAuthConfig, eventSimpleFactoryImpl, eventRESTClientImpl, cvePolicyRepositoryImpl, imageScanResultRepositoryImpl, appWorkflowRepositoryImpl, prePostCdScriptHistoryServiceImpl, argoUserServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineStatusTimelineServiceImpl, ciTemplateRepositoryImpl, ciWorkflowRepositoryImpl, appLabelRepositoryImpl, clientImpl, pipelineStageServiceImpl, k8sCommonServiceImpl, variableSnapshotHistoryServiceImpl, globalPluginServiceImpl, pluginInputVariableParserImpl, scopedVariableCMCSManagerImpl, deploymentTemplateHistoryServiceImpl, configMapHistoryServiceImpl, pipelineStrategyHistoryServiceImpl, manifestPushConfigRepositoryImpl, gitOpsManifestPushServiceImpl, ciPipelineMaterialRepositoryImpl, imageScanHistoryRepositoryImpl, imageScanDeployInfoRepositoryImpl, appCrudOperationServiceImpl, pipelineConfigRepositoryImpl, dockerRegistryIpsConfigServiceImpl, chartRepositoryImpl, chartTemplateServiceImpl, pipelineStrategyHistoryRepositoryImpl, appRepositoryImpl, deploymentTemplateHistoryRepositoryImpl, argoK8sClientImpl, configMapRepositoryImpl, configMapHistoryRepositoryImpl, refChartDir, helmAppServiceImpl, helmAppClientImpl, chartRefRepositoryImpl, envConfigOverrideRepositoryImpl, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, dbMigrationConfigRepositoryImpl, mergeUtil, gitOpsConfigRepositoryImpl, gitFactory, applicationServiceClientImpl, argoClientWrapperServiceImpl, pipelineConfigListenerServiceImpl, customTagServiceImpl, acdConfig) deploymentGroupAppRepositoryImpl := repository.NewDeploymentGroupAppRepositoryImpl(sugaredLogger, db) deploymentGroupServiceImpl := deploymentGroup.NewDeploymentGroupServiceImpl(appRepositoryImpl, sugaredLogger, pipelineRepositoryImpl, ciPipelineRepositoryImpl, deploymentGroupRepositoryImpl, environmentRepositoryImpl, deploymentGroupAppRepositoryImpl, ciArtifactRepositoryImpl, appWorkflowRepositoryImpl, workflowDagExecutorImpl) deploymentConfigServiceImpl := pipeline.NewDeploymentConfigServiceImpl(sugaredLogger, envConfigOverrideRepositoryImpl, chartRepositoryImpl, pipelineRepositoryImpl, envLevelAppMetricsRepositoryImpl, appLevelMetricsRepositoryImpl, pipelineConfigRepositoryImpl, configMapRepositoryImpl, configMapHistoryServiceImpl, chartRefRepositoryImpl, scopedVariableCMCSManagerImpl) @@ -522,7 +526,7 @@ func InitializeApp() (*App, error) { linkoutsRepositoryImpl := repository.NewLinkoutsRepositoryImpl(sugaredLogger, db) appListingServiceImpl := app2.NewAppListingServiceImpl(sugaredLogger, appListingRepositoryImpl, applicationServiceClientImpl, appRepositoryImpl, appListingViewBuilderImpl, pipelineRepositoryImpl, linkoutsRepositoryImpl, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, environmentRepositoryImpl, argoUserServiceImpl, envConfigOverrideRepositoryImpl, chartRepositoryImpl, ciPipelineRepositoryImpl, dockerRegistryIpsConfigServiceImpl, userRepositoryImpl) deploymentEventHandlerImpl := app2.NewDeploymentEventHandlerImpl(sugaredLogger, appListingServiceImpl, eventRESTClientImpl, eventSimpleFactoryImpl) - cdHandlerImpl := pipeline.NewCdHandlerImpl(sugaredLogger, userServiceImpl, cdWorkflowRepositoryImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, ciPipelineMaterialRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, ciWorkflowRepositoryImpl, helmAppServiceImpl, pipelineOverrideRepositoryImpl, workflowDagExecutorImpl, appListingServiceImpl, appListingRepositoryImpl, pipelineStatusTimelineRepositoryImpl, applicationServiceClientImpl, argoUserServiceImpl, deploymentEventHandlerImpl, eventRESTClientImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceImpl, appStatusServiceImpl, enforcerUtilImpl, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appRepositoryImpl, resourceGroupServiceImpl, imageTaggingServiceImpl, k8sUtil, workflowServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl, customTagServiceImpl) + cdHandlerImpl := pipeline.NewCdHandlerImpl(sugaredLogger, userServiceImpl, cdWorkflowRepositoryImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, ciPipelineMaterialRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, ciWorkflowRepositoryImpl, helmAppServiceImpl, pipelineOverrideRepositoryImpl, workflowDagExecutorImpl, appListingServiceImpl, appListingRepositoryImpl, pipelineStatusTimelineRepositoryImpl, applicationServiceClientImpl, argoUserServiceImpl, deploymentEventHandlerImpl, eventRESTClientImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceImpl, appStatusServiceImpl, enforcerUtilImpl, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appRepositoryImpl, resourceGroupServiceImpl, imageTaggingServiceImpl, k8sUtil, workflowServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl, customTagServiceImpl, argoClientWrapperServiceImpl, appServiceConfig, acdConfig) appWorkflowServiceImpl := appWorkflow2.NewAppWorkflowServiceImpl(sugaredLogger, appWorkflowRepositoryImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, appRepositoryImpl, userAuthServiceImpl) appCloneServiceImpl := appClone.NewAppCloneServiceImpl(sugaredLogger, pipelineBuilderImpl, materialRepositoryImpl, chartServiceImpl, configMapServiceImpl, appWorkflowServiceImpl, appListingServiceImpl, propertiesConfigServiceImpl, ciTemplateOverrideRepositoryImpl, pipelineStageServiceImpl, ciTemplateServiceImpl, appRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, appWorkflowRepositoryImpl, ciPipelineConfigServiceImpl) deploymentTemplateRepositoryImpl := repository.NewDeploymentTemplateRepositoryImpl(db, sugaredLogger) @@ -554,7 +558,7 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - installedAppServiceImpl, err := service.NewInstalledAppServiceImpl(sugaredLogger, installedAppRepositoryImpl, chartTemplateServiceImpl, refChartProxyDir, repositoryServiceClientImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, teamRepositoryImpl, appRepositoryImpl, applicationServiceClientImpl, appStoreValuesServiceImpl, pubSubClientServiceImpl, tokenCache, chartGroupDeploymentRepositoryImpl, environmentServiceImpl, argoK8sClientImpl, gitFactory, acdAuthConfig, gitOpsConfigRepositoryImpl, userServiceImpl, appStoreDeploymentFullModeServiceImpl, appStoreDeploymentServiceImpl, installedAppVersionHistoryRepositoryImpl, argoUserServiceImpl, helmAppClientImpl, helmAppServiceImpl, attributesRepositoryImpl, appStatusServiceImpl, k8sUtil, pipelineStatusTimelineServiceImpl, appStoreDeploymentCommonServiceImpl, appStoreDeploymentArgoCdServiceImpl, k8sCommonServiceImpl, k8sApplicationServiceImpl) + installedAppServiceImpl, err := service.NewInstalledAppServiceImpl(sugaredLogger, installedAppRepositoryImpl, chartTemplateServiceImpl, refChartProxyDir, repositoryServiceClientImpl, appStoreApplicationVersionRepositoryImpl, environmentRepositoryImpl, teamRepositoryImpl, appRepositoryImpl, applicationServiceClientImpl, appStoreValuesServiceImpl, pubSubClientServiceImpl, tokenCache, chartGroupDeploymentRepositoryImpl, environmentServiceImpl, argoK8sClientImpl, gitFactory, acdAuthConfig, gitOpsConfigRepositoryImpl, userServiceImpl, appStoreDeploymentFullModeServiceImpl, appStoreDeploymentServiceImpl, installedAppVersionHistoryRepositoryImpl, argoUserServiceImpl, helmAppClientImpl, helmAppServiceImpl, attributesRepositoryImpl, appStatusServiceImpl, k8sUtil, pipelineStatusTimelineServiceImpl, appStoreDeploymentCommonServiceImpl, appStoreDeploymentArgoCdServiceImpl, k8sCommonServiceImpl, k8sApplicationServiceImpl, acdConfig) if err != nil { return nil, err } @@ -751,7 +755,7 @@ func InitializeApp() (*App, error) { deploymentConfigRouterImpl := deployment.NewDeploymentRouterImpl(deploymentConfigRestHandlerImpl) dashboardTelemetryRestHandlerImpl := dashboardEvent.NewDashboardTelemetryRestHandlerImpl(sugaredLogger, telemetryEventClientImplExtended) dashboardTelemetryRouterImpl := dashboardEvent.NewDashboardTelemetryRouterImpl(dashboardTelemetryRestHandlerImpl) - commonDeploymentRestHandlerImpl := appStoreDeployment.NewCommonDeploymentRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, appStoreDeploymentServiceImpl, validate, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, helmAppRestHandlerImpl) + commonDeploymentRestHandlerImpl := appStoreDeployment.NewCommonDeploymentRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, appStoreDeploymentServiceImpl, validate, helmAppServiceImpl, appStoreDeploymentCommonServiceImpl, helmAppRestHandlerImpl, argoUserServiceImpl) commonDeploymentRouterImpl := appStoreDeployment.NewCommonDeploymentRouterImpl(commonDeploymentRestHandlerImpl) externalLinkMonitoringToolRepositoryImpl := externalLink.NewExternalLinkMonitoringToolRepositoryImpl(db) externalLinkIdentifierMappingRepositoryImpl := externalLink.NewExternalLinkIdentifierMappingRepositoryImpl(db)