diff --git a/api/restHandler/CoreAppRestHandler.go b/api/restHandler/CoreAppRestHandler.go index bb8581dcfc..eff6fba1c0 100644 --- a/api/restHandler/CoreAppRestHandler.go +++ b/api/restHandler/CoreAppRestHandler.go @@ -1847,11 +1847,11 @@ func (handler CoreAppRestHandlerImpl) createEnvDeploymentTemplate(appId int, use templateRequest := bean3.TemplateRequest{ AppId: appId, ChartRefId: chartRefId, - ValuesOverride: []byte("{}"), + ValuesOverride: util.GetEmptyJSON(), UserId: userId, IsAppMetricsEnabled: deploymentTemplateOverride.ShowAppMetrics, } - newChartEntry, err := handler.chartService.CreateChartFromEnvOverride(templateRequest, context.Background()) + newChartEntry, err := handler.chartService.CreateChartFromEnvOverride(context.Background(), templateRequest) if err != nil { handler.logger.Errorw("service err, CreateChartFromEnvOverride", "err", err, "appId", appId, "envId", envId, "chartRefId", chartRefId) return err diff --git a/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go b/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go index 52728940d5..59b4c4bc1a 100644 --- a/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go +++ b/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler.go @@ -21,11 +21,10 @@ import ( "encoding/json" "errors" "fmt" + models2 "github.com/devtron-labs/devtron/internal/sql/models" bean3 "github.com/devtron-labs/devtron/pkg/chart/bean" - bean4 "github.com/devtron-labs/devtron/pkg/auth/user/bean" devtronAppGitOpConfigBean "github.com/devtron-labs/devtron/pkg/chart/gitOpsConfig/bean" - chartRefBean "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" "io" "net/http" @@ -106,6 +105,8 @@ type DevtronAppDeploymentConfigRestHandler interface { GetDefaultDeploymentPipelineStrategy(w http.ResponseWriter, r *http.Request) EnvConfigOverrideCreateNamespace(w http.ResponseWriter, r *http.Request) + + DevtronAppDeploymentConfigRestHandlerEnt } type DevtronAppPrePostDeploymentRestHandler interface { @@ -136,7 +137,7 @@ func (handler *PipelineConfigRestHandlerImpl) ConfigureDeploymentTemplateForApp( return } chartRefId := templateRequest.ChartRefId - //VARIABLE_RESOLVE + // VARIABLE_RESOLVE scope := resourceQualifiers.Scope{ AppId: templateRequest.AppId, } @@ -222,7 +223,8 @@ func (handler *PipelineConfigRestHandlerImpl) CreateCdPipeline(w http.ResponseWr common.WriteJsonResp(w, fmt.Errorf("cannot create cd-pipeline for job"), "cannot create cd-pipeline for job", http.StatusBadRequest) return } - //RBAC + + // RBAC resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) @@ -259,8 +261,7 @@ func (handler *PipelineConfigRestHandlerImpl) CreateCdPipeline(w http.ResponseWr return } } - //RBAC - + // RBAC createResp, err := handler.pipelineBuilder.CreateCdPipelines(&cdPipeline, r.Context()) if err != nil { @@ -347,8 +348,8 @@ func (handler *PipelineConfigRestHandlerImpl) PatchCdPipeline(w http.ResponseWri common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - ctx := r.Context() - createResp, err := handler.pipelineBuilder.PatchCdPipelines(&cdPipeline, ctx) + + createResp, err := handler.pipelineBuilder.PatchCdPipelines(&cdPipeline, r.Context()) if err != nil { handler.Logger.Errorw("service err, PatchCdPipeline", "err", err, "payload", cdPipeline) @@ -534,6 +535,7 @@ func (handler *PipelineConfigRestHandlerImpl) ChangeChartRef(w http.ResponseWrit common.WriteJsonResp(w, err, request, http.StatusBadRequest) return } + handler.Logger.Infow("request payload, EnvConfigOverrideCreate", "payload", request) envConfigProperties, err := handler.propertiesConfigService.GetLatestEnvironmentProperties(request.AppId, request.EnvId) if err != nil || envConfigProperties == nil { handler.Logger.Errorw("env properties not found, ChangeChartRef", "err", err, "payload", request) @@ -542,43 +544,21 @@ func (handler *PipelineConfigRestHandlerImpl) ChangeChartRef(w http.ResponseWrit } if !envConfigProperties.IsOverride { handler.Logger.Errorw("isOverride is not true, ChangeChartRef", "err", err, "payload", request) - common.WriteJsonResp(w, err, "specific environment is not overriden", http.StatusUnprocessableEntity) + common.WriteJsonResp(w, err, "specific environment is not overridden", http.StatusUnprocessableEntity) return } - compatible, oldChartType, newChartType := handler.chartRefService.ChartRefIdsCompatible(envConfigProperties.ChartRefId, request.TargetChartRefId) - if !compatible { - common.WriteJsonResp(w, fmt.Errorf("charts not compatible"), "chart not compatible", http.StatusUnprocessableEntity) - return - } - - envConfigProperties.EnvOverrideValues, err = handler.chartService.PatchEnvOverrides(envConfigProperties.EnvOverrideValues, oldChartType, newChartType) - if err != nil { - common.WriteJsonResp(w, err, "error in patching env override", http.StatusInternalServerError) - return - } - - if newChartType == chartRefBean.RolloutChartType { - enabled, err := handler.deploymentTemplateValidationService.FlaggerCanaryEnabled(envConfigProperties.EnvOverrideValues) - if err != nil || enabled { - handler.Logger.Errorw("rollout charts do not support flaggerCanary, ChangeChartRef", "err", err, "payload", request) - common.WriteJsonResp(w, err, "rollout charts do not support flaggerCanary, ChangeChartRef", http.StatusBadRequest) - return - } - } - - envMetrics, err := handler.deployedAppMetricsService.GetMetricsFlagByAppIdAndEnvId(request.AppId, request.EnvId) + token := r.Header.Get("token") + ctx := util2.SetTokenInContext(r.Context(), token) + var envMetrics bool + envConfigProperties, envMetrics, err = handler.deploymentTemplateValidationService.ValidateChangeChartRefRequest(ctx, envConfigProperties, &request) if err != nil { - handler.Logger.Errorw("could not find envMetrics for, ChangeChartRef", "err", err, "payload", request) - common.WriteJsonResp(w, err, "env metric could not be fetched", http.StatusBadRequest) + handler.Logger.Errorw("validation err, ChangeChartRef", "err", err, "payload", request) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - envConfigProperties.ChartRefId = request.TargetChartRefId envConfigProperties.UserId = userId - envConfigProperties.EnvironmentId = request.EnvId - envConfigProperties.AppMetrics = &envMetrics - - token := r.Header.Get("token") - handler.Logger.Infow("request payload, EnvConfigOverrideCreate", "payload", request) + request.EnvConfigProperties = envConfigProperties + request.EnvMetrics = envMetrics resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(request.AppId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) @@ -589,78 +569,26 @@ func (handler *PipelineConfigRestHandlerImpl) ChangeChartRef(w http.ResponseWrit common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - - //VARIABLE_RESOLVE - scope := resourceQualifiers.Scope{ - AppId: request.AppId, - EnvId: request.EnvId, - ClusterId: envConfigProperties.ClusterId, - } - validate, err2 := handler.deploymentTemplateValidationService.DeploymentTemplateValidate(r.Context(), envConfigProperties.EnvOverrideValues, envConfigProperties.ChartRefId, scope) - if !validate { - handler.Logger.Errorw("validation err, UpdateAppOverride", "err", err2, "payload", request) - common.WriteJsonResp(w, err2, "validation err, UpdateAppOverrid", http.StatusBadRequest) - return - } - envConfigPropertiesOld, err := handler.propertiesConfigService.FetchEnvProperties(request.AppId, request.EnvId, request.TargetChartRefId) - if err == nil { - envConfigProperties.Id = envConfigPropertiesOld.Id - createResp, err := handler.propertiesConfigService.UpdateEnvironmentProperties(request.AppId, envConfigProperties, userId) - if err != nil { - handler.Logger.Errorw("service err, EnvConfigOverrideUpdate", "err", err, "payload", envConfigProperties) - common.WriteJsonResp(w, err, createResp, http.StatusInternalServerError) - return - } - common.WriteJsonResp(w, err, createResp, http.StatusOK) - return + newCtx, cancel := context.WithCancel(ctx) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(newCtx.Done(), cn.CloseNotify()) } - createResp, err := handler.propertiesConfigService.CreateEnvironmentProperties(request.AppId, envConfigProperties) - + envConfigProperties.MergeStrategy = models2.MERGE_STRATEGY_REPLACE // always replace + createResp, err := handler.propertiesConfigService.ChangeChartRefForEnvConfigOverride(newCtx, &request, userId) if err != nil { - if err.Error() == bean4.NOCHARTEXIST { - 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()) - } - appMetrics := false - if envConfigProperties.AppMetrics != nil { - appMetrics = envMetrics - } - templateRequest := bean3.TemplateRequest{ - AppId: request.AppId, - ChartRefId: request.TargetChartRefId, - ValuesOverride: []byte("{}"), - UserId: userId, - IsAppMetricsEnabled: appMetrics, - } - - _, err = handler.chartService.CreateChartFromEnvOverride(templateRequest, ctx) - if err != nil { - handler.Logger.Errorw("service err, CreateChartFromEnvOverride", "err", err, "payload", request) - common.WriteJsonResp(w, err, "could not create chart from env override", http.StatusInternalServerError) - return - } - createResp, err = handler.propertiesConfigService.CreateEnvironmentProperties(request.AppId, envConfigProperties) - if err != nil { - handler.Logger.Errorw("service err, CreateEnvironmentProperties", "err", err, "payload", request) - common.WriteJsonResp(w, err, "could not create env properties", http.StatusInternalServerError) - return - } - common.WriteJsonResp(w, err, createResp, http.StatusOK) - return - } else { - handler.Logger.Errorw("service err, EnvConfigOverrideCreate", "err", err, "payload", request) - common.WriteJsonResp(w, err, "service err, EnvConfigOverrideCreate", http.StatusInternalServerError) - return - } + handler.Logger.Errorw("service err, ChangeChartRef", "err", err, "payload", request) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return } common.WriteJsonResp(w, err, createResp, http.StatusOK) + return } func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideCreate(w http.ResponseWriter, r *http.Request) { @@ -704,7 +632,7 @@ func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideCreate(w http.Res return } chartRefId := envConfigProperties.ChartRefId - //VARIABLE_RESOLVE + // VARIABLE_RESOLVE scope := resourceQualifiers.Scope{ AppId: appId, EnvId: environmentId, @@ -739,7 +667,7 @@ func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideCreate(w http.Res func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideUpdate(w http.ResponseWriter, r *http.Request) { decoder := json.NewDecoder(r.Body) - //userId := getLoggedInUser(r) + // userId := getLoggedInUser(r) userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) @@ -780,7 +708,7 @@ func (handler *PipelineConfigRestHandlerImpl) EnvConfigOverrideUpdate(w http.Res return } chartRefId := envConfigProperties.ChartRefId - //VARIABLE_RESOLVE + // VARIABLE_RESOLVE scope := resourceQualifiers.Scope{ AppId: appId, EnvId: envId, @@ -851,6 +779,11 @@ func (handler *PipelineConfigRestHandlerImpl) GetEnvConfigOverride(w http.Respon func (handler *PipelineConfigRestHandlerImpl) GetTemplateComparisonMetadata(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) + userId, err := handler.userAuthService.GetLoggedInUser(r) + if userId == 0 || err != nil { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } token := r.Header.Get("token") appId, err := strconv.Atoi(vars["appId"]) if err != nil { @@ -870,7 +803,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetTemplateComparisonMetadata(w ht common.WriteJsonResp(w, err, "unauthorized user", http.StatusForbidden) return } - //RBAC enforcer Ends + // RBAC enforcer Ends resp, err := handler.deploymentTemplateService.FetchDeploymentsWithChartRefs(appId, envId) if err != nil { @@ -878,7 +811,6 @@ func (handler *PipelineConfigRestHandlerImpl) GetTemplateComparisonMetadata(w ht common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - common.WriteJsonResp(w, nil, resp, http.StatusOK) } @@ -908,12 +840,12 @@ func (handler *PipelineConfigRestHandlerImpl) GetDeploymentTemplateData(w http.R return } isSuperAdmin := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*") - //RBAC enforcer Ends + // RBAC enforcer Ends ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second) ctx = util2.SetSuperAdminInContext(ctx, isSuperAdmin) defer cancel() - //TODO fix + // TODO fix resp, err := handler.deploymentTemplateService.GetDeploymentTemplate(ctx, request) if err != nil { handler.Logger.Errorw("service err, GetEnvConfigOverride", "err", err, "payload", request) @@ -922,6 +854,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetDeploymentTemplateData(w http.R } common.WriteJsonResp(w, nil, resp, http.StatusOK) } + func (handler *PipelineConfigRestHandlerImpl) GetRestartWorkloadData(w http.ResponseWriter, r *http.Request) { userId, err := handler.userAuthService.GetLoggedInUser(r) if userId == 0 || err != nil { @@ -954,6 +887,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetRestartWorkloadData(w http.Resp } common.WriteJsonResp(w, nil, resp, http.StatusOK) } + func (handler *PipelineConfigRestHandlerImpl) filterAuthorizedResourcesForGroup(appIds []int, envId int, token string) []int { appToEnv := make(map[int][]int) @@ -1108,7 +1042,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCdPipelinesForAppAndEnv(w http. common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - //rbac + // rbac resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) @@ -1119,7 +1053,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetCdPipelinesForAppAndEnv(w http. common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - //rbac + // rbac cdPipelines, err := handler.pipelineBuilder.GetCdPipelinesForAppAndEnv(appId, envId) if err != nil { @@ -1132,10 +1066,15 @@ func (handler *PipelineConfigRestHandlerImpl) GetCdPipelinesForAppAndEnv(w http. func (handler *PipelineConfigRestHandlerImpl) GetArtifactsByCDPipeline(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("token") + userId, err := handler.userAuthService.GetLoggedInUser(r) + if userId == 0 || err != nil { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } vars := mux.Vars(r) cdPipelineId, err := strconv.Atoi(vars["cd_pipeline_id"]) if err != nil { - handler.Logger.Errorw("request err, GetArtifactsByCDPipeline", "err", err, "cdPipelineId", cdPipelineId) + handler.Logger.Errorw("request err, GetArtifactsByCDPipeline", "cdPipelineId", cdPipelineId, "err", err) common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } @@ -1155,7 +1094,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsByCDPipeline(w http.Re if offsetQueryParam != "" { offset, err = strconv.Atoi(offsetQueryParam) if err != nil || offset < 0 { - handler.Logger.Errorw("request err, GetArtifactsForRollback", "err", err, "offsetQueryParam", offsetQueryParam) + handler.Logger.Errorw("request err, GetArtifactsForRollback", "offsetQueryParam", offsetQueryParam, "err", err) common.WriteJsonResp(w, err, "invalid offset", http.StatusBadRequest) return } @@ -1165,7 +1104,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsByCDPipeline(w http.Re if sizeQueryParam != "" { limit, err = strconv.Atoi(sizeQueryParam) if err != nil { - handler.Logger.Errorw("request err, GetArtifactsForRollback", "err", err, "sizeQueryParam", sizeQueryParam) + handler.Logger.Errorw("request err, GetArtifactsForRollback", "sizeQueryParam", sizeQueryParam, "err", err) common.WriteJsonResp(w, err, "invalid size", http.StatusBadRequest) return } @@ -1174,50 +1113,45 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsByCDPipeline(w http.Re pipeline, err := handler.pipelineBuilder.FindPipelineById(cdPipelineId) if err != nil { + handler.Logger.Errorw("service err, FindPipelineById", "stage", stage, "cdPipelineId", cdPipelineId, "err", err) common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - if err != nil { - handler.Logger.Errorw("service err, GetArtifactsByCDPipeline", "err", err, "cdPipelineId", cdPipelineId, "stage", stage) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) - return - } - - //rbac block starts from here + // rbac block starts from here object := handler.enforcerUtil.GetAppRBACName(pipeline.App.AppName) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - //rbac for edit tags access + // rbac for edit tags access triggerAccess := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, object) - //rbac + // rbac object = handler.enforcerUtil.GetAppRBACByAppNameAndEnvId(pipeline.App.AppName, pipeline.EnvironmentId) if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionGet, object); !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } - //rbac block ends here + // rbac block ends here artifactsListFilterOptions := &bean2.ArtifactsListFilterOptions{ Limit: limit, Offset: offset, SearchString: searchString, } - //RetrieveArtifactsByCDPipeline is deprecated and method is removed from code - //ciArtifactResponse, err = handler.pipelineBuilder.RetrieveArtifactsByCDPipeline(pipeline, bean2.WorkflowType(stage)) + // RetrieveArtifactsByCDPipeline is deprecated and method is removed from code + // ciArtifactResponse, err = handler.pipelineBuilder.RetrieveArtifactsByCDPipeline(pipeline, bean2.WorkflowType(stage)) ciArtifactResponse, err := handler.pipelineBuilder.RetrieveArtifactsByCDPipelineV2(pipeline, bean2.WorkflowType(stage), artifactsListFilterOptions) if err != nil { - handler.Logger.Errorw("service err, GetArtifactsByCDPipeline", "err", err, "cdPipelineId", cdPipelineId, "stage", stage) + handler.Logger.Errorw("service err, GetArtifactsByCDPipeline", "cdPipelineId", cdPipelineId, "stage", stage, "err", err) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } appTags, err := handler.imageTaggingReadService.GetUniqueTagsByAppId(pipeline.AppId) if err != nil { - handler.Logger.Errorw("service err, GetTagsByAppId", "err", err, "appId", pipeline.AppId) + handler.Logger.Errorw("service err, GetTagsByAppId", "appId", pipeline.AppId, "err", err) common.WriteJsonResp(w, err, ciArtifactResponse, http.StatusInternalServerError) return } @@ -1228,7 +1162,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsByCDPipeline(w http.Re ciArtifactResponse.TagsEditable = prodEnvExists && triggerAccess ciArtifactResponse.HideImageTaggingHardDelete = handler.imageTaggingService.IsHardDeleteHidden() if err != nil { - handler.Logger.Errorw("service err, GetProdEnvByCdPipelineId", "err", err, "cdPipelineId", pipeline.Id) + handler.Logger.Errorw("service err, GetProdEnvByCdPipelineId", "cdPipelineId", pipeline.Id, "err", err) common.WriteJsonResp(w, err, ciArtifactResponse, http.StatusInternalServerError) return } @@ -1241,7 +1175,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsByCDPipeline(w http.Re } if len(digests) > 0 { - //vulnerableMap := make(map[string]bool) + // vulnerableMap := make(map[string]bool) cvePolicy, severityPolicy, err := handler.policyService.GetApplicablePolicy(pipeline.Environment.ClusterId, pipeline.EnvironmentId, pipeline.AppId, @@ -1267,7 +1201,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsByCDPipeline(w http.Re if val, ok := digestVsCveStores[imageHash]; !ok { // configuring size as len of ImageScanExecutionResult assuming all the - //scan results could belong to a single hash + // scan results could belong to a single hash cveStores := make([]*repository.CveStore, 0, len(imageScanResults)) cveStores = append(cveStores, &result.CveStore) digestVsCveStores[imageHash] = cveStores @@ -1313,13 +1247,13 @@ func (handler *PipelineConfigRestHandlerImpl) GetAppOverrideForDefaultTemplate(w return } - //RBAC + // RBAC object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } - //RBAC + // RBAC appOverride, _, err := handler.chartRefService.GetAppOverrideForDefaultTemplate(chartRefId) if err != nil { @@ -1371,7 +1305,7 @@ func (handler *PipelineConfigRestHandlerImpl) UpdateAppOverride(w http.ResponseW return } chartRefId := templateRequest.ChartRefId - //VARIABLE_RESOLVE + // VARIABLE_RESOLVE scope := resourceQualifiers.Scope{ AppId: templateRequest.AppId, } @@ -1396,6 +1330,11 @@ func (handler *PipelineConfigRestHandlerImpl) UpdateAppOverride(w http.ResponseW } func (handler *PipelineConfigRestHandlerImpl) GetArtifactsForRollback(w http.ResponseWriter, r *http.Request) { + userId, err := handler.userAuthService.GetLoggedInUser(r) + if userId == 0 || err != nil { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } vars := mux.Vars(r) cdPipelineId, err := strconv.Atoi(vars["cd_pipeline_id"]) if err != nil { @@ -1433,7 +1372,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsForRollback(w http.Res } searchString := r.URL.Query().Get("search") - //rbac block starts from here + // rbac block starts from here object := handler.enforcerUtil.GetAppRBACName(app.AppName) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) @@ -1444,8 +1383,8 @@ func (handler *PipelineConfigRestHandlerImpl) GetArtifactsForRollback(w http.Res common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } - //rbac block ends here - //rbac for edit tags access + // rbac block ends here + // rbac for edit tags access var ciArtifactResponse bean.CiArtifactResponse triggerAccess := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, object) if handler.pipelineRestHandlerEnvConfig.UseArtifactListApiV2 { @@ -1569,13 +1508,13 @@ func (handler *PipelineConfigRestHandlerImpl) ListDeploymentHistory(w http.Respo return } handler.Logger.Infow("request payload, ListDeploymentHistory", "err", err, "appId", appId, "environmentId", environmentId, "pipelineId", pipelineId, "offset", offset) - //RBAC CHECK + // RBAC CHECK resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - //RBAC CHECK + // RBAC CHECK resp := DeploymentHistoryResp{} wfs, err := handler.cdHandler.GetCdBuildHistory(appId, environmentId, pipelineId, offset, limit) resp.CdWorkflows = wfs @@ -1635,13 +1574,13 @@ func (handler *PipelineConfigRestHandlerImpl) GetPrePostDeploymentLogs(w http.Re } handler.Logger.Infow("request payload, GetPrePostDeploymentLogs", "err", err, "appId", appId, "environmentId", environmentId, "pipelineId", pipelineId, "workflowId", workflowId) - //RBAC CHECK + // RBAC CHECK resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - //RBAC CHECK + // RBAC CHECK logsReader, cleanUp, err := handler.cdHandler.GetRunningWorkflowLogs(environmentId, pipelineId, workflowId) if err != nil { @@ -1708,13 +1647,13 @@ func (handler *PipelineConfigRestHandlerImpl) FetchCdWorkflowDetails(w http.Resp } handler.Logger.Infow("request payload, FetchCdWorkflowDetails", "err", err, "appId", appId, "environmentId", environmentId, "pipelineId", pipelineId, "buildId", buildId) - //RBAC CHECK + // RBAC CHECK resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - //RBAC CHECK + // RBAC CHECK resp, err := handler.cdHandler.FetchCdWorkflowDetails(appId, environmentId, pipelineId, buildId) if err != nil { @@ -1755,7 +1694,7 @@ func (handler *PipelineConfigRestHandlerImpl) DownloadArtifacts(w http.ResponseW } handler.Logger.Infow("request payload, DownloadArtifacts", "err", err, "appId", appId, "pipelineId", pipelineId, "buildId", buildId) - //RBAC CHECK + // RBAC CHECK resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) @@ -1766,7 +1705,7 @@ func (handler *PipelineConfigRestHandlerImpl) DownloadArtifacts(w http.ResponseW common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - //RBAC CHECK + // RBAC CHECK file, err := handler.cdHandler.DownloadCdWorkflowArtifacts(buildId) defer file.Close() @@ -1810,7 +1749,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetStageStatus(w http.ResponseWrit } handler.Logger.Infow("request payload, GetStageStatus", "err", err, "appId", appId, "pipelineId", pipelineId) - //RBAC CHECK + // RBAC CHECK resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) @@ -1821,7 +1760,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetStageStatus(w http.ResponseWrit common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } - //RBAC CHECK + // RBAC CHECK resp, err := handler.cdHandler.FetchCdPrePostStageStatus(pipelineId) if err != nil { @@ -1855,8 +1794,8 @@ func (handler *PipelineConfigRestHandlerImpl) GetConfigmapSecretsForDeploymentSt common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - //FIXME: add RBAC - resp, err := handler.pipelineBuilder.FetchConfigmapSecretsForCdStages(deploymentPipeline.AppId, deploymentPipeline.EnvironmentId, pipelineId) + // FIXME: add RBAC + resp, err := handler.pipelineBuilder.FetchConfigmapSecretsForCdStages(deploymentPipeline.AppId, deploymentPipeline.EnvironmentId) if err != nil { handler.Logger.Errorw("service err, GetConfigmapSecretsForDeploymentStages", "err", err, "pipelineId", pipelineId) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) @@ -1943,14 +1882,14 @@ func (handler *PipelineConfigRestHandlerImpl) CancelStage(w http.ResponseWriter, } handler.Logger.Infow("request payload, CancelStage", "pipelineId", pipelineId, "workflowRunnerId", workflowRunnerId) - //RBAC + // RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(cdPipeline.AppId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, object); !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } - //RBAC + // RBAC resp, err := handler.cdHandler.CancelStage(workflowRunnerId, forceAbort, userId) if err != nil { @@ -1974,13 +1913,13 @@ func (handler *PipelineConfigRestHandlerImpl) GetDeploymentPipelineStrategy(w ht return } handler.Logger.Infow("request payload, GetDeploymentPipelineStrategy", "appId", appId) - //RBAC + // RBAC object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } - //RBAC + // RBAC result, err := handler.pipelineBuilder.FetchCDPipelineStrategy(appId) if err != nil { @@ -1991,6 +1930,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetDeploymentPipelineStrategy(w ht common.WriteJsonResp(w, err, result, http.StatusOK) } + func (handler *PipelineConfigRestHandlerImpl) GetDefaultDeploymentPipelineStrategy(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("token") vars := mux.Vars(r) @@ -2005,13 +1945,13 @@ func (handler *PipelineConfigRestHandlerImpl) GetDefaultDeploymentPipelineStrate return } handler.Logger.Infow("request payload, GetDefaultDeploymentPipelineStrategy", "appId", appId, "envId", envId) - //RBAC + // RBAC object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } - //RBAC + // RBAC result, err := handler.pipelineBuilder.FetchDefaultCDPipelineStrategy(appId, envId) if err != nil { @@ -2094,7 +2034,7 @@ func (handler *PipelineConfigRestHandlerImpl) IsReadyToTrigger(w http.ResponseWr return } handler.Logger.Infow("request payload, IsReadyToTrigger", "appId", appId, "envId", envId, "pipelineId", pipelineId) - //RBAC + // RBAC object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) @@ -2105,7 +2045,7 @@ func (handler *PipelineConfigRestHandlerImpl) IsReadyToTrigger(w http.ResponseWr common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } - //RBAC + // RBAC result, err := handler.chartService.IsReadyToTrigger(appId, envId, pipelineId) if err != nil { @@ -2186,7 +2126,7 @@ func (handler *PipelineConfigRestHandlerImpl) UpgradeForAllApps(w http.ResponseW var failedIds []map[string]string for _, appId := range appIds { appResponse := make(map[string]string) - template, err := handler.chartService.GetByAppIdAndChartRefId(appId, chartRefId) + template, err := handler.chartReadService.GetByAppIdAndChartRefId(appId, chartRefId) if err != nil && pg.ErrNoRows != err { handler.Logger.Errorw("err in checking weather exist or not, skip for upgrade", "err", err, "payload", chartUpgradeRequest) appResponse["appId"] = strconv.Itoa(appId) diff --git a/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler_ent.go b/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler_ent.go new file mode 100644 index 0000000000..e678aeeb26 --- /dev/null +++ b/api/restHandler/app/pipeline/configure/DeploymentPipelineRestHandler_ent.go @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020-2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package configure + +type DevtronAppDeploymentConfigRestHandlerEnt interface { +} diff --git a/api/restHandler/app/pipeline/configure/PipelineConfigRestHandler.go b/api/restHandler/app/pipeline/configure/PipelineConfigRestHandler.go index 5e3e81defd..1aa5bd7a3f 100644 --- a/api/restHandler/app/pipeline/configure/PipelineConfigRestHandler.go +++ b/api/restHandler/app/pipeline/configure/PipelineConfigRestHandler.go @@ -30,8 +30,8 @@ import ( read5 "github.com/devtron-labs/devtron/pkg/chart/read" repository2 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deployedAppMetrics" - "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef" + validator2 "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/validator" security2 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning" "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/read" read3 "github.com/devtron-labs/devtron/pkg/team/read" @@ -108,7 +108,7 @@ type PipelineConfigRestHandlerImpl struct { ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository ciHandler pipeline.CiHandler Logger *zap.SugaredLogger - deploymentTemplateValidationService deploymentTemplate.DeploymentTemplateValidationService + deploymentTemplateValidationService validator2.DeploymentTemplateValidationService chartService chart.ChartService devtronAppGitOpConfigService gitOpsConfig.DevtronAppGitOpConfigService propertiesConfigService pipeline.PropertiesConfigService @@ -141,7 +141,7 @@ type PipelineConfigRestHandlerImpl struct { } func NewPipelineRestHandlerImpl(pipelineBuilder pipeline.PipelineBuilder, Logger *zap.SugaredLogger, - deploymentTemplateValidationService deploymentTemplate.DeploymentTemplateValidationService, + deploymentTemplateValidationService validator2.DeploymentTemplateValidationService, chartService chart.ChartService, devtronAppGitOpConfigService gitOpsConfig.DevtronAppGitOpConfigService, propertiesConfigService pipeline.PropertiesConfigService, diff --git a/internal/sql/repository/chartConfig/PipelineConfigRepository.go b/internal/sql/repository/chartConfig/PipelineConfigRepository.go index 68a95b4783..b2baa46daa 100644 --- a/internal/sql/repository/chartConfig/PipelineConfigRepository.go +++ b/internal/sql/repository/chartConfig/PipelineConfigRepository.go @@ -42,7 +42,7 @@ type PipelineConfigRepository interface { FindByStrategyAndPipelineId(strategy chartRepoRepository.DeploymentStrategy, pipelineId int) (pipelineStrategy *PipelineStrategy, err error) GetAllStrategyByPipelineId(pipelineId int) ([]*PipelineStrategy, error) GetDefaultStrategyByPipelineId(pipelineId int) (pipelineStrategy *PipelineStrategy, err error) - Delete(pipelineStrategy *PipelineStrategy, tx *pg.Tx) error + MarkAsDeleted(pipelineStrategy *PipelineStrategy, userId int32, tx *pg.Tx) error GetAllStrategyByPipelineIds(pipelineIds []int) ([]*PipelineStrategy, error) } @@ -59,21 +59,25 @@ func (impl PipelineConfigRepositoryImpl) Save(pipelineStrategy *PipelineStrategy } func (impl PipelineConfigRepositoryImpl) Update(pipelineStrategy *PipelineStrategy, tx *pg.Tx) error { - _, err := impl.dbConnection.Model(pipelineStrategy).WherePK().UpdateNotNull() + _, err := tx.Model(pipelineStrategy).WherePK().UpdateNotNull() return err } func (impl PipelineConfigRepositoryImpl) FindById(id int) (pipelineStrategy *PipelineStrategy, err error) { pipelineStrategy = &PipelineStrategy{} err = impl.dbConnection.Model(pipelineStrategy). - Where("id = ?", id).Select() + Where("id = ?", id). + Where("deleted = ?", false). + Select() return pipelineStrategy, err } func (impl PipelineConfigRepositoryImpl) FindByStrategy(strategy chartRepoRepository.DeploymentStrategy) (pipelineStrategy *PipelineStrategy, err error) { pipelineStrategy = &PipelineStrategy{} err = impl.dbConnection.Model(pipelineStrategy). - Where("strategy = ?", strategy).Select() + Where("strategy = ?", strategy). + Where("deleted = ?", false). + Select() return pipelineStrategy, err } @@ -81,11 +85,15 @@ func (impl PipelineConfigRepositoryImpl) FindByStrategyAndPipelineId(strategy ch pipelineStrategy = &PipelineStrategy{} err = impl.dbConnection.Model(pipelineStrategy). Where("strategy = ?", strategy). - Where("pipeline_id = ?", pipelineId).Select() + Where("pipeline_id = ?", pipelineId). + Where("deleted = ?", false). + Select() return pipelineStrategy, err } -// it will return for multiple pipeline config for pipeline, per pipeline single pipeline config(blue green, canary) +// GetAllStrategyByPipelineId - +// it will return for multiple pipeline strategies for a pipeline +// per pipeline single pipeline strategy (BLUE_GREEN, CANARY, ROLLING, RECREATE) can be there func (impl PipelineConfigRepositoryImpl) GetAllStrategyByPipelineId(pipelineId int) ([]*PipelineStrategy, error) { var pipelineStrategies []*PipelineStrategy err := impl.dbConnection. @@ -99,7 +107,8 @@ func (impl PipelineConfigRepositoryImpl) GetAllStrategyByPipelineId(pipelineId i return pipelineStrategies, err } -// it will return single latest pipeline config for requested pipeline +// GetDefaultStrategyByPipelineId - +// it will return single latest pipeline strategy for the requested pipeline func (impl PipelineConfigRepositoryImpl) GetDefaultStrategyByPipelineId(pipelineId int) (pipelineStrategy *PipelineStrategy, err error) { pipelineStrategy = &PipelineStrategy{} err = impl.dbConnection. @@ -114,8 +123,12 @@ func (impl PipelineConfigRepositoryImpl) GetDefaultStrategyByPipelineId(pipeline return pipelineStrategy, err } -func (impl PipelineConfigRepositoryImpl) Delete(pipelineStrategy *PipelineStrategy, tx *pg.Tx) error { - return tx.Delete(pipelineStrategy) +// MarkAsDeleted - +// it will soft-delete the pipeline strategy from the database +func (impl PipelineConfigRepositoryImpl) MarkAsDeleted(pipelineStrategy *PipelineStrategy, userId int32, tx *pg.Tx) error { + pipelineStrategy.Deleted = true + pipelineStrategy.UpdateAuditLog(userId) + return impl.Update(pipelineStrategy, tx) } func (impl PipelineConfigRepositoryImpl) GetAllStrategyByPipelineIds(pipelineIds []int) ([]*PipelineStrategy, error) { diff --git a/internal/sql/repository/chartConfig/mocks/PipelineConfigRepository.go b/internal/sql/repository/chartConfig/mocks/PipelineConfigRepository.go index 7122cb2671..fc244d9ab1 100644 --- a/internal/sql/repository/chartConfig/mocks/PipelineConfigRepository.go +++ b/internal/sql/repository/chartConfig/mocks/PipelineConfigRepository.go @@ -16,8 +16,8 @@ type PipelineConfigRepository struct { mock.Mock } -// Delete provides a mock function with given fields: pipelineStrategy, tx -func (_m *PipelineConfigRepository) Delete(pipelineStrategy *chartConfig.PipelineStrategy, tx *pg.Tx) error { +// MarkAsDeleted provides a mock function with given fields: pipelineStrategy, tx +func (_m *PipelineConfigRepository) MarkAsDeleted(pipelineStrategy *chartConfig.PipelineStrategy, userId int32, tx *pg.Tx) error { ret := _m.Called(pipelineStrategy, tx) var r0 error diff --git a/internal/util/ChartTemplateService.go b/internal/util/ChartTemplateService.go index 0fe4098b7d..0f72eb550f 100644 --- a/internal/util/ChartTemplateService.go +++ b/internal/util/ChartTemplateService.go @@ -63,7 +63,7 @@ type ChartCreateResponse struct { } type ChartTemplateService interface { - FetchValuesFromReferenceChart(chartMetaData *chart.Metadata, refChartLocation string, templateName string, userId int32, pipelineStrategyPath string) (*ChartValues, error) + FetchValuesFromReferenceChart(chartMetaData *chart.Metadata, refChartLocation string, pipelineStrategyPath string) (*ChartValues, error) GetChartVersion(location string) (string, error) BuildChart(ctx context.Context, chartMetaData *chart.Metadata, referenceTemplatePath string) (string, error) BuildChartProxyForHelmApps(chartCreateRequest *ChartCreateRequest) (chartCreateResponse *ChartCreateResponse, err error) @@ -116,7 +116,7 @@ func (impl ChartTemplateServiceImpl) GetChartVersion(location string) (string, e return chartContent.Version, nil } -func (impl ChartTemplateServiceImpl) FetchValuesFromReferenceChart(chartMetaData *chart.Metadata, refChartLocation string, templateName string, userId int32, pipelineStrategyPath string) (*ChartValues, error) { +func (impl ChartTemplateServiceImpl) FetchValuesFromReferenceChart(chartMetaData *chart.Metadata, refChartLocation string, pipelineStrategyPath string) (*ChartValues, error) { chartMetaData.APIVersion = "v1" // ensure always v1 dir := impl.GetDir() chartDir := filepath.Join(CHART_WORKING_DIR_PATH, dir) diff --git a/pkg/app/AppService.go b/pkg/app/AppService.go index 5bb33db0c8..47620046df 100644 --- a/pkg/app/AppService.go +++ b/pkg/app/AppService.go @@ -128,7 +128,8 @@ type AppServiceImpl struct { type AppService interface { UpdateReleaseStatus(request *bean.ReleaseStatusUpdateRequest) (bool, error) - GetConfigMapAndSecretJson(appId int, envId int, pipelineId int) ([]byte, error) + // Deprecated: GetConfigMapAndSecretJson + GetConfigMapAndSecretJson(appId int, envId int) ([]byte, error) UpdateCdWorkflowRunnerByACDObject(app *v1alpha1.Application, cdWfrId int, updateTimedOutStatus bool) error UpdateDeploymentStatusForGitOpsPipelines(app *v1alpha1.Application, applicationClusterId int, statusTime time.Time, isAppStore bool) (bool, bool, *chartConfig.PipelineOverride, error) WriteCDSuccessEvent(appId int, envId int, override *chartConfig.PipelineOverride) @@ -807,15 +808,14 @@ func (impl *AppServiceImpl) CreateGitOpsRepo(app *app.App, targetRevision string return gitOpsRepoName, chartGitAttr, nil } -// depricated -// TODO remove this method -func (impl *AppServiceImpl) GetConfigMapAndSecretJson(appId int, envId int, pipelineId int) ([]byte, error) { +// GetConfigMapAndSecretJson TODO remove this method +func (impl *AppServiceImpl) GetConfigMapAndSecretJson(appId int, envId int) ([]byte, error) { var configMapJson string var secretDataJson string - merged := []byte("{}") + merged := globalUtil.GetEmptyJSON() configMapA, err := impl.configMapRepository.GetByAppIdAppLevel(appId) if err != nil && pg.ErrNoRows != err { - return []byte("{}"), err + return merged, err } if configMapA != nil && configMapA.Id > 0 { configMapJson = configMapA.ConfigMapData @@ -828,17 +828,17 @@ func (impl *AppServiceImpl) GetConfigMapAndSecretJson(appId int, envId int, pipe } config, err := impl.mergeUtil.JsonPatch([]byte(configMapJson), []byte(secretDataJson)) if err != nil { - return []byte("{}"), err + return merged, err } merged, err = impl.mergeUtil.JsonPatch(merged, config) if err != nil { - return []byte("{}"), err + return merged, err } } configMapE, err := impl.configMapRepository.GetByAppIdAndEnvIdEnvLevel(appId, envId) if err != nil && pg.ErrNoRows != err { - return []byte("{}"), err + return globalUtil.GetEmptyJSON(), err } if configMapE != nil && configMapE.Id > 0 { configMapJson = configMapE.ConfigMapData @@ -851,11 +851,11 @@ func (impl *AppServiceImpl) GetConfigMapAndSecretJson(appId int, envId int, pipe } config, err := impl.mergeUtil.JsonPatch([]byte(configMapJson), []byte(secretDataJson)) if err != nil { - return []byte("{}"), err + return merged, err } merged, err = impl.mergeUtil.JsonPatch(merged, config) if err != nil { - return []byte("{}"), err + return merged, err } } diff --git a/pkg/appClone/AppCloneService.go b/pkg/appClone/AppCloneService.go index 61813b2bde..7a083e2ec9 100644 --- a/pkg/appClone/AppCloneService.go +++ b/pkg/appClone/AppCloneService.go @@ -39,6 +39,7 @@ import ( "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/pipeline" bean3 "github.com/devtron-labs/devtron/pkg/pipeline/bean" + globalUtil "github.com/devtron-labs/devtron/util" "github.com/go-pg/pg" "go.uber.org/zap" "net/http" @@ -528,12 +529,12 @@ func (impl *AppCloneServiceImpl) createEnvOverride(oldAppId, newAppId int, userI templateRequest := bean5.TemplateRequest{ AppId: newAppId, ChartRefId: envPropertiesReq.ChartRefId, - ValuesOverride: []byte("{}"), + ValuesOverride: globalUtil.GetEmptyJSON(), UserId: userId, IsBasicViewLocked: envPropertiesReq.IsBasicViewLocked, CurrentViewEditor: envPropertiesReq.CurrentViewEditor, } - _, err = impl.chartService.CreateChartFromEnvOverride(templateRequest, ctx) + _, err = impl.chartService.CreateChartFromEnvOverride(ctx, templateRequest) if err != nil { impl.logger.Error(err) return nil, nil diff --git a/pkg/appClone/batch/Deployment_test.go b/pkg/appClone/batch/Deployment_test.go index c6f724954e..7051babb4b 100644 --- a/pkg/appClone/batch/Deployment_test.go +++ b/pkg/appClone/batch/Deployment_test.go @@ -110,7 +110,7 @@ func Test_transformStrategy(t *testing.T) { }, bean.Strategy{ DeploymentTemplate: "RECREATE", - Config: []byte("{}"), + Config: globalUtil.GetEmptyJSON(), Default: false, }}, wantErr: false, diff --git a/pkg/chart/ChartService.go b/pkg/chart/ChartService.go index 452f85dcfd..358ff5c317 100644 --- a/pkg/chart/ChartService.go +++ b/pkg/chart/ChartService.go @@ -26,6 +26,7 @@ import ( "github.com/devtron-labs/devtron/internal/sql/repository/app" "github.com/devtron-labs/devtron/internal/sql/repository/chartConfig" "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/chart/adaptor" bean3 "github.com/devtron-labs/devtron/pkg/chart/bean" read2 "github.com/devtron-labs/devtron/pkg/chart/read" chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" @@ -58,14 +59,12 @@ import ( type ChartService interface { Create(templateRequest bean3.TemplateRequest, ctx context.Context) (chart *bean3.TemplateRequest, err error) - CreateChartFromEnvOverride(templateRequest bean3.TemplateRequest, ctx context.Context) (chart *bean3.TemplateRequest, err error) - GetByAppIdAndChartRefId(appId int, chartRefId int) (chartTemplate *bean3.TemplateRequest, err error) + CreateChartFromEnvOverride(ctx context.Context, templateRequest bean3.TemplateRequest) (chart *bean3.TemplateRequest, err error) UpdateAppOverride(ctx context.Context, templateRequest *bean3.TemplateRequest) (*bean3.TemplateRequest, error) IsReadyToTrigger(appId int, envId int, pipelineId int) (IsReady, error) FindPreviousChartByAppId(appId int) (chartTemplate *bean3.TemplateRequest, err error) UpgradeForApp(appId int, chartRefId int, newAppOverride map[string]interface{}, userId int32, ctx context.Context) (bool, error) CheckIfChartRefUserUploadedByAppId(id int) (bool, error) - PatchEnvOverrides(values json.RawMessage, oldChartType string, newChartType string) (json.RawMessage, error) ChartRefAutocompleteGlobalData() (*chartRefBean.ChartRefAutocompleteResponse, error) ChartRefAutocompleteForAppOrEnv(appId int, envId int) (*chartRefBean.ChartRefAutocompleteResponse, error) @@ -76,6 +75,8 @@ type ChartService interface { IsGitOpsRepoAlreadyRegistered(gitOpsRepoUrl string) (bool, error) GetDeploymentTemplateDataByAppIdAndCharRefId(appId, chartRefId int) (map[string]interface{}, error) + + ChartServiceEnt } type ChartServiceImpl struct { @@ -136,11 +137,9 @@ func NewChartServiceImpl(chartRepository chartRepoRepository.ChartRepository, } } -func (impl *ChartServiceImpl) PatchEnvOverrides(values json.RawMessage, oldChartType string, newChartType string) (json.RawMessage, error) { - return PatchWinterSoldierConfig(values, newChartType) -} - func (impl *ChartServiceImpl) Create(templateRequest bean3.TemplateRequest, ctx context.Context) (*bean3.TemplateRequest, error) { + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "ChartServiceImpl.Create") + defer span.End() err := impl.chartRefService.CheckChartExists(templateRequest.ChartRefId) if err != nil { impl.logger.Errorw("error in getting missing chart for chartRefId", "err", err, "chartRefId") @@ -237,7 +236,7 @@ func (impl *ChartServiceImpl) Create(templateRequest bean3.TemplateRequest, ctx if err != nil { return nil, err } - chartValues, err := impl.chartTemplateService.FetchValuesFromReferenceChart(chartMeta, refChart, templateName, templateRequest.UserId, pipelineStrategyPath) + chartValues, err := impl.chartTemplateService.FetchValuesFromReferenceChart(chartMeta, refChart, pipelineStrategyPath) if err != nil { return nil, err } @@ -341,13 +340,13 @@ func (impl *ChartServiceImpl) Create(templateRequest bean3.TemplateRequest, ctx ChartRefId: templateRequest.ChartRefId, UserId: templateRequest.UserId, } - err = impl.deployedAppMetricsService.CreateOrUpdateAppOrEnvLevelMetrics(ctx, appLevelMetricsUpdateReq) + err = impl.deployedAppMetricsService.CreateOrUpdateAppOrEnvLevelMetrics(newCtx, appLevelMetricsUpdateReq) if err != nil { impl.logger.Errorw("error, CheckAndUpdateAppOrEnvLevelMetrics", "err", err, "req", appLevelMetricsUpdateReq) return nil, err } - chartVal, err := impl.chartAdaptor(chart, appLevelMetricsUpdateReq.EnableMetrics, deploymentConfig) + chartVal, err := adaptor.ChartAdaptor(chart, appLevelMetricsUpdateReq.EnableMetrics, deploymentConfig) return chartVal, err } @@ -371,7 +370,9 @@ func (impl *ChartServiceImpl) UpdateChartLocationForEnvironmentConfigs(appId, ch return nil } -func (impl *ChartServiceImpl) CreateChartFromEnvOverride(templateRequest bean3.TemplateRequest, ctx context.Context) (*bean3.TemplateRequest, error) { +func (impl *ChartServiceImpl) CreateChartFromEnvOverride(ctx context.Context, templateRequest bean3.TemplateRequest) (*bean3.TemplateRequest, error) { + _, span := otel.Tracer("orchestrator").Start(ctx, "ChartServiceImpl.CreateChartFromEnvOverride") + defer span.End() err := impl.chartRefService.CheckChartExists(templateRequest.ChartRefId) if err != nil { impl.logger.Errorw("error in getting missing chart for chartRefId", "err", err, "chartRefId") @@ -409,7 +410,7 @@ func (impl *ChartServiceImpl) CreateChartFromEnvOverride(templateRequest bean3.T if err != nil { return nil, err } - chartValues, err := impl.chartTemplateService.FetchValuesFromReferenceChart(chartMeta, refChart, templateName, templateRequest.UserId, pipelineStrategyPath) + chartValues, err := impl.chartTemplateService.FetchValuesFromReferenceChart(chartMeta, refChart, pipelineStrategyPath) if err != nil { return nil, err } @@ -504,43 +505,10 @@ func (impl *ChartServiceImpl) CreateChartFromEnvOverride(templateRequest bean3.T return nil, err } - chartVal, err := impl.chartAdaptor(chart, false, deploymentConfig) + chartVal, err := adaptor.ChartAdaptor(chart, false, deploymentConfig) return chartVal, err } -// converts db object to bean -func (impl *ChartServiceImpl) chartAdaptor(chart *chartRepoRepository.Chart, isAppMetricsEnabled bool, deploymentConfig *bean2.DeploymentConfig) (*bean3.TemplateRequest, error) { - if chart == nil || chart.Id == 0 { - return &bean3.TemplateRequest{}, &util.ApiError{UserMessage: "no chart found"} - } - var gitRepoUrl, targetRevision string - if !apiGitOpsBean.IsGitOpsRepoNotConfigured(deploymentConfig.GetRepoURL()) { - gitRepoUrl = deploymentConfig.GetRepoURL() - targetRevision = deploymentConfig.GetTargetRevision() - } - templateRequest := &bean3.TemplateRequest{ - RefChartTemplate: chart.ReferenceTemplate, - Id: chart.Id, - AppId: chart.AppId, - ChartRepositoryId: chart.ChartRepoId, - DefaultAppOverride: json.RawMessage(chart.GlobalOverride), - RefChartTemplateVersion: impl.getParentChartVersion(chart.ChartVersion), - Latest: chart.Latest, - ChartRefId: chart.ChartRefId, - IsAppMetricsEnabled: isAppMetricsEnabled, - IsBasicViewLocked: chart.IsBasicViewLocked, - CurrentViewEditor: chart.CurrentViewEditor, - GitRepoUrl: gitRepoUrl, - TargetRevision: targetRevision, - IsCustomGitRepository: deploymentConfig.ConfigType == bean2.CUSTOM.String(), - ImageDescriptorTemplate: chart.ImageDescriptorTemplate, - } - if chart.Latest { - templateRequest.LatestChartVersion = chart.ChartVersion - } - return templateRequest, nil -} - func (impl *ChartServiceImpl) getChartMetaData(templateRequest bean3.TemplateRequest) (*chart.Metadata, error) { pg, err := impl.pipelineGroupRepository.FindById(templateRequest.AppId) if err != nil { @@ -570,11 +538,6 @@ func (impl *ChartServiceImpl) getChartRepo(templateRequest bean3.TemplateRequest } } -func (impl *ChartServiceImpl) getParentChartVersion(childVersion string) string { - placeholders := strings.Split(childVersion, ".") - return fmt.Sprintf("%s.%s.0", placeholders[0], placeholders[1]) -} - // this method is not thread safe func (impl *ChartServiceImpl) getNewVersion(chartRepo, chartName, refChartLocation string) (string, error) { parentVersion, err := impl.chartTemplateService.GetChartVersion(refChartLocation) @@ -618,29 +581,10 @@ func (impl *ChartServiceImpl) IsGitOpsRepoConfiguredForDevtronApp(appId int) (bo return !apiGitOpsBean.IsGitOpsRepoNotConfigured(latestChartConfiguredInApp.GitRepoUrl), nil } -func (impl *ChartServiceImpl) GetByAppIdAndChartRefId(appId int, chartRefId int) (chartTemplate *bean3.TemplateRequest, err error) { - chart, err := impl.chartRepository.FindChartByAppIdAndRefId(appId, chartRefId) - if err != nil { - impl.logger.Errorw("error in fetching chart ", "appId", appId, "err", err) - return nil, err - } - isAppMetricsEnabled, err := impl.deployedAppMetricsService.GetMetricsFlagByAppId(appId) - if err != nil { - impl.logger.Errorw("error in fetching app-metrics", "appId", appId, "err", err) - return nil, err - } - deploymentConfig, err := impl.deploymentConfigService.GetConfigForDevtronApps(appId, 0) - if err != nil { - impl.logger.Errorw("error in fetching deployment config by appId", "appId", appId, "err", err) - return nil, err - } - chartTemplate, err = impl.chartAdaptor(chart, isAppMetricsEnabled, deploymentConfig) - return chartTemplate, err -} - func (impl *ChartServiceImpl) UpdateAppOverride(ctx context.Context, templateRequest *bean3.TemplateRequest) (*bean3.TemplateRequest, error) { - - _, span := otel.Tracer("orchestrator").Start(ctx, "chartRepository.FindById") + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "ChartServiceImpl.UpdateAppOverride") + defer span.End() + _, span = otel.Tracer("orchestrator").Start(newCtx, "chartRepository.FindById") template, err := impl.chartRepository.FindById(templateRequest.Id) span.End() if err != nil { @@ -648,13 +592,8 @@ func (impl *ChartServiceImpl) UpdateAppOverride(ctx context.Context, templateReq return nil, err } - if err != nil { - impl.logger.Errorw("chart version parsing", "err", err) - return nil, err - } - - //STARTS - _, span = otel.Tracer("orchestrator").Start(ctx, "chartRepository.FindLatestChartForAppByAppId") + // STARTS + _, span = otel.Tracer("orchestrator").Start(newCtx, "chartRepository.FindLatestChartForAppByAppId") currentLatestChart, err := impl.chartRepository.FindLatestChartForAppByAppId(templateRequest.AppId) span.End() if err != nil { @@ -683,7 +622,7 @@ func (impl *ChartServiceImpl) UpdateAppOverride(ctx context.Context, templateReq } defer impl.chartRepository.RollbackTx(tx) - _, span = otel.Tracer("orchestrator").Start(ctx, "chartRepository.FindNoLatestChartForAppByAppId") + _, span = otel.Tracer("orchestrator").Start(newCtx, "chartRepository.FindNoLatestChartForAppByAppId") noLatestCharts, dbErr := impl.chartRepository.FindNoLatestChartForAppByAppId(templateRequest.AppId) span.End() if dbErr != nil && !util.IsErrNoRows(dbErr) { @@ -698,7 +637,7 @@ func (impl *ChartServiceImpl) UpdateAppOverride(ctx context.Context, templateReq updatedCharts = append(updatedCharts, noLatestChart) } } - _, span = otel.Tracer("orchestrator").Start(ctx, "chartRepository.Update") + _, span = otel.Tracer("orchestrator").Start(newCtx, "chartRepository.Update") err = impl.chartRepository.UpdateAllInTx(tx, updatedCharts) span.End() if err != nil { @@ -715,7 +654,7 @@ func (impl *ChartServiceImpl) UpdateAppOverride(ctx context.Context, templateReq // now finally update latest entry in db to false and previous true currentLatestChart.Latest = false // these are already false by d way currentLatestChart.Previous = true - _, span = otel.Tracer("orchestrator").Start(ctx, "chartRepository.Update.LatestChart") + _, span = otel.Tracer("orchestrator").Start(newCtx, "chartRepository.Update.LatestChart") err = impl.chartRepository.Update(currentLatestChart) span.End() if err != nil { @@ -731,7 +670,7 @@ func (impl *ChartServiceImpl) UpdateAppOverride(ctx context.Context, templateReq } else { return nil, nil } - //ENDS + // ENDS impl.logger.Debug("now finally update request chart in db to latest and previous flag = false") values, err := impl.mergeUtil.JsonPatch([]byte(template.Values), templateRequest.ValuesOverride) @@ -746,7 +685,7 @@ func (impl *ChartServiceImpl) UpdateAppOverride(ctx context.Context, templateReq template.Previous = false template.IsBasicViewLocked = templateRequest.IsBasicViewLocked template.CurrentViewEditor = templateRequest.CurrentViewEditor - _, span = otel.Tracer("orchestrator").Start(ctx, "chartRepository.Update.requestTemplate") + _, span = otel.Tracer("orchestrator").Start(newCtx, "chartRepository.Update.requestTemplate") err = impl.chartRepository.Update(template) span.End() if err != nil { @@ -790,12 +729,12 @@ func (impl *ChartServiceImpl) UpdateAppOverride(ctx context.Context, templateReq ChartRefId: templateRequest.ChartRefId, UserId: templateRequest.UserId, } - err = impl.deployedAppMetricsService.CreateOrUpdateAppOrEnvLevelMetrics(ctx, appLevelMetricsUpdateReq) + err = impl.deployedAppMetricsService.CreateOrUpdateAppOrEnvLevelMetrics(newCtx, appLevelMetricsUpdateReq) if err != nil { impl.logger.Errorw("error, CheckAndUpdateAppOrEnvLevelMetrics", "err", err, "req", appLevelMetricsUpdateReq) return nil, err } - _, span = otel.Tracer("orchestrator").Start(ctx, "CreateDeploymentTemplateHistoryFromGlobalTemplate") + _, span = otel.Tracer("orchestrator").Start(newCtx, "CreateDeploymentTemplateHistoryFromGlobalTemplate") //creating history entry for deployment template err = impl.deploymentTemplateHistoryService.CreateDeploymentTemplateHistoryFromGlobalTemplate(template, nil, appLevelMetricsUpdateReq.EnableMetrics) span.End() @@ -919,7 +858,7 @@ func (impl *ChartServiceImpl) FindPreviousChartByAppId(appId int) (chartTemplate impl.logger.Errorw("error in fetching deployment config by appId", "appId", appId, "err", err) return nil, err } - chartTemplate, err = impl.chartAdaptor(chart, false, deploymentConfig) + chartTemplate, err = adaptor.ChartAdaptor(chart, false, deploymentConfig) return chartTemplate, err } @@ -1163,7 +1102,7 @@ func (impl *ChartServiceImpl) GetDeploymentTemplateDataByAppIdAndCharRefId(appId appConfigResponse["globalConfig"] = json.RawMessage(mapB) } else { if template.ChartRefId != chartRefId { - templateRequested, err := impl.GetByAppIdAndChartRefId(appId, chartRefId) + templateRequested, err := impl.chartReadService.GetByAppIdAndChartRefId(appId, chartRefId) if err != nil && err != pg.ErrNoRows { impl.logger.Errorw("service err, GetDeploymentTemplate", "err", err, "appId", appId, "chartRefId", chartRefId) return nil, err diff --git a/pkg/chart/ChartService_ent.go b/pkg/chart/ChartService_ent.go new file mode 100644 index 0000000000..7f7033f611 --- /dev/null +++ b/pkg/chart/ChartService_ent.go @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020-2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package chart + +type ChartServiceEnt interface { +} diff --git a/pkg/chart/adaptor/adaptor.go b/pkg/chart/adaptor/adaptor.go new file mode 100644 index 0000000000..8354ee1601 --- /dev/null +++ b/pkg/chart/adaptor/adaptor.go @@ -0,0 +1,53 @@ +package adaptor + +import ( + "encoding/json" + "fmt" + apiGitOpsBean "github.com/devtron-labs/devtron/api/bean/gitOps" + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/chart/bean" + chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" + bean2 "github.com/devtron-labs/devtron/pkg/deployment/common/bean" + util2 "github.com/devtron-labs/devtron/util" + "strings" +) + +// ChartAdaptor converts db object chartRepoRepository.Chart to bean.TemplateRequest +func ChartAdaptor(chartModel *chartRepoRepository.Chart, + isAppMetricsEnabled bool, deploymentConfig *bean2.DeploymentConfig) (*bean.TemplateRequest, error) { + if chartModel == nil || chartModel.Id == 0 { + return &bean.TemplateRequest{}, &util.ApiError{UserMessage: "no chartInput found"} + } + gitRepoUrl := "" + targetRevision := util2.GetDefaultTargetRevision() + if !apiGitOpsBean.IsGitOpsRepoNotConfigured(deploymentConfig.GetRepoURL()) { + gitRepoUrl = deploymentConfig.GetRepoURL() + targetRevision = deploymentConfig.GetTargetRevision() + } + templateRequest := &bean.TemplateRequest{ + RefChartTemplate: chartModel.ReferenceTemplate, + Id: chartModel.Id, + AppId: chartModel.AppId, + ChartRepositoryId: chartModel.ChartRepoId, + DefaultAppOverride: json.RawMessage(chartModel.GlobalOverride), + RefChartTemplateVersion: getParentChartVersion(chartModel.ChartVersion), + Latest: chartModel.Latest, + ChartRefId: chartModel.ChartRefId, + IsAppMetricsEnabled: isAppMetricsEnabled, + IsBasicViewLocked: chartModel.IsBasicViewLocked, + CurrentViewEditor: chartModel.CurrentViewEditor, + GitRepoUrl: gitRepoUrl, + IsCustomGitRepository: deploymentConfig.ConfigType == bean2.CUSTOM.String(), + ImageDescriptorTemplate: chartModel.ImageDescriptorTemplate, + TargetRevision: targetRevision, + } + if chartModel.Latest { + templateRequest.LatestChartVersion = chartModel.ChartVersion + } + return templateRequest, nil +} + +func getParentChartVersion(childVersion string) string { + placeholders := strings.Split(childVersion, ".") + return fmt.Sprintf("%s.%s.0", placeholders[0], placeholders[1]) +} diff --git a/pkg/chart/bean/bean.go b/pkg/chart/bean/bean.go index abcc28bdfe..0eb09655ab 100644 --- a/pkg/chart/bean/bean.go +++ b/pkg/chart/bean/bean.go @@ -19,6 +19,7 @@ package bean import ( "encoding/json" "github.com/devtron-labs/devtron/internal/sql/models" + bean2 "github.com/devtron-labs/devtron/pkg/pipeline/bean" ) var ReservedChartRefNamesList *[]ReservedChartList @@ -59,9 +60,12 @@ type ChartUpgradeRequest struct { } type ChartRefChangeRequest struct { - AppId int `json:"appId" validate:"required"` - EnvId int `json:"envId" validate:"required"` - TargetChartRefId int `json:"targetChartRefId" validate:"required"` + AppId int `json:"appId" validate:"required"` + EnvId int `json:"envId" validate:"required"` + TargetChartRefId int `json:"targetChartRefId" validate:"required"` + EnvConfigProperties *bean2.EnvironmentProperties `json:"-"` + EnvMetrics bool `json:"-"` + UserId int32 `json:"-"` } type PipelineConfigRequest struct { diff --git a/pkg/chart/read/ChartReadService.go b/pkg/chart/read/ChartReadService.go index 7019ec3594..b338c2e560 100644 --- a/pkg/chart/read/ChartReadService.go +++ b/pkg/chart/read/ChartReadService.go @@ -1,21 +1,16 @@ package read import ( - "encoding/json" - "fmt" apiGitOpsBean "github.com/devtron-labs/devtron/api/bean/gitOps" - "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/chart/adaptor" "github.com/devtron-labs/devtron/pkg/chart/bean" chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" "github.com/devtron-labs/devtron/pkg/deployment/common" - bean2 "github.com/devtron-labs/devtron/pkg/deployment/common/bean" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deployedAppMetrics" bean3 "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" chartRefRead "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/read" - util2 "github.com/devtron-labs/devtron/util" "go.uber.org/zap" - "strings" ) type ChartReadService interface { @@ -67,7 +62,7 @@ func (impl *ChartReadServiceImpl) GetByAppIdAndChartRefId(appId int, chartRefId impl.logger.Errorw("error in fetching deployment config by appId", "appId", appId, "err", err) return nil, err } - chartTemplate, err = impl.chartAdaptor(chart, isAppMetricsEnabled, deploymentConfig) + chartTemplate, err = adaptor.ChartAdaptor(chart, isAppMetricsEnabled, deploymentConfig) return chartTemplate, err } @@ -113,44 +108,10 @@ func (impl *ChartReadServiceImpl) FindLatestChartForAppByAppId(appId int) (chart impl.logger.Errorw("error in fetching app-metrics", "appId", appId, "err", err) return nil, err } - chartTemplate, err = impl.chartAdaptor(chart, isAppMetricsEnabled, deploymentConfig) + chartTemplate, err = adaptor.ChartAdaptor(chart, isAppMetricsEnabled, deploymentConfig) return chartTemplate, err } -// converts db object to bean -func (impl *ChartReadServiceImpl) chartAdaptor(chartInput *chartRepoRepository.Chart, isAppMetricsEnabled bool, deploymentConfig *bean2.DeploymentConfig) (*bean.TemplateRequest, error) { - if chartInput == nil || chartInput.Id == 0 { - return &bean.TemplateRequest{}, &util.ApiError{UserMessage: "no chartInput found"} - } - gitRepoUrl := "" - targetRevision := util2.GetDefaultTargetRevision() - if !apiGitOpsBean.IsGitOpsRepoNotConfigured(deploymentConfig.GetRepoURL()) { - gitRepoUrl = deploymentConfig.GetRepoURL() - targetRevision = deploymentConfig.GetTargetRevision() - } - templateRequest := &bean.TemplateRequest{ - RefChartTemplate: chartInput.ReferenceTemplate, - Id: chartInput.Id, - AppId: chartInput.AppId, - ChartRepositoryId: chartInput.ChartRepoId, - DefaultAppOverride: json.RawMessage(chartInput.GlobalOverride), - RefChartTemplateVersion: impl.getParentChartVersion(chartInput.ChartVersion), - Latest: chartInput.Latest, - ChartRefId: chartInput.ChartRefId, - IsAppMetricsEnabled: isAppMetricsEnabled, - IsBasicViewLocked: chartInput.IsBasicViewLocked, - CurrentViewEditor: chartInput.CurrentViewEditor, - GitRepoUrl: gitRepoUrl, - IsCustomGitRepository: deploymentConfig.ConfigType == bean2.CUSTOM.String(), - ImageDescriptorTemplate: chartInput.ImageDescriptorTemplate, - TargetRevision: targetRevision, - } - if chartInput.Latest { - templateRequest.LatestChartVersion = chartInput.ChartVersion - } - return templateRequest, nil -} - func (impl *ChartReadServiceImpl) GetChartRefConfiguredForApp(appId int) (*bean3.ChartRefDto, error) { latestChart, err := impl.FindLatestChartForAppByAppId(appId) if err != nil { @@ -164,8 +125,3 @@ func (impl *ChartReadServiceImpl) GetChartRefConfiguredForApp(appId int) (*bean3 } return chartRef, nil } - -func (impl *ChartReadServiceImpl) getParentChartVersion(childVersion string) string { - placeholders := strings.Split(childVersion, ".") - return fmt.Sprintf("%s.%s.0", placeholders[0], placeholders[1]) -} diff --git a/pkg/deployment/manifest/ManifestCreationService.go b/pkg/deployment/manifest/ManifestCreationService.go index fa0a4c2ca3..da286d1bdf 100644 --- a/pkg/deployment/manifest/ManifestCreationService.go +++ b/pkg/deployment/manifest/ManifestCreationService.go @@ -556,7 +556,7 @@ func (impl *ManifestCreationServiceImpl) mergeOverrideValues(envOverride *bean2. } else { templateOverrideValuesByte = []byte(envOverride.ResolvedEnvOverrideValues) } - merged, err = impl.mergeUtil.JsonPatch([]byte("{}"), templateOverrideValuesByte) + merged, err = impl.mergeUtil.JsonPatch(globalUtil.GetEmptyJSON(), templateOverrideValuesByte) if err != nil { impl.logger.Errorw("error in merging deployment template override values", "err", err, "overrideValues", templateOverrideValuesByte) return nil, err diff --git a/pkg/deployment/manifest/deployedAppMetrics/DeployedAppMetrics.go b/pkg/deployment/manifest/deployedAppMetrics/DeployedAppMetrics.go index 086b02e0bf..5be28200b3 100644 --- a/pkg/deployment/manifest/deployedAppMetrics/DeployedAppMetrics.go +++ b/pkg/deployment/manifest/deployedAppMetrics/DeployedAppMetrics.go @@ -30,6 +30,7 @@ import ( ) type DeployedAppMetricsService interface { + CheckIsAppMetricsSupported(chartRefId int) (bool, error) GetMetricsFlagByAppId(appId int) (bool, error) GetMetricsFlagByAppIdAndEnvId(appId, envId int) (bool, error) GetMetricsFlagForAPipelineByAppIdAndEnvId(appId, envId int) (bool, error) @@ -104,7 +105,7 @@ func (impl *DeployedAppMetricsServiceImpl) GetMetricsFlagForAPipelineByAppIdAndE // CheckAndUpdateAppOrEnvLevelMetrics - this method checks whether chart being used supports metrics or not, is app level or env level and updates accordingly func (impl *DeployedAppMetricsServiceImpl) CreateOrUpdateAppOrEnvLevelMetrics(ctx context.Context, req *bean.DeployedAppMetricsRequest) error { - isAppMetricsSupported, err := impl.checkIsAppMetricsSupported(req.ChartRefId) + isAppMetricsSupported, err := impl.CheckIsAppMetricsSupported(req.ChartRefId) if err != nil { return err } @@ -148,7 +149,7 @@ func (impl *DeployedAppMetricsServiceImpl) DeleteEnvLevelMetricsIfPresent(appId, return nil } -func (impl *DeployedAppMetricsServiceImpl) checkIsAppMetricsSupported(chartRefId int) (bool, error) { +func (impl *DeployedAppMetricsServiceImpl) CheckIsAppMetricsSupported(chartRefId int) (bool, error) { chartRefValue, err := impl.chartRefService.FindById(chartRefId) if err != nil { impl.logger.Errorw("error in finding reference chart by id", "err", err) diff --git a/pkg/deployment/manifest/deployedAppMetrics/repository/AppLevelMetricsRepository.go b/pkg/deployment/manifest/deployedAppMetrics/repository/AppLevelMetricsRepository.go index ca68dadf60..d520f52b9a 100644 --- a/pkg/deployment/manifest/deployedAppMetrics/repository/AppLevelMetricsRepository.go +++ b/pkg/deployment/manifest/deployedAppMetrics/repository/AppLevelMetricsRepository.go @@ -33,7 +33,7 @@ type AppLevelMetrics struct { type AppLevelMetricsRepository interface { Save(metrics *AppLevelMetrics) error - FindByAppId(id int) (*AppLevelMetrics, error) + FindByAppId(appId int) (*AppLevelMetrics, error) Update(metrics *AppLevelMetrics) error } diff --git a/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartRefService.go b/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartRefService.go index 7ac9d8915e..d61d17ffe1 100644 --- a/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartRefService.go +++ b/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartRefService.go @@ -29,6 +29,7 @@ import ( "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/read" util2 "github.com/devtron-labs/devtron/util" + "github.com/go-pg/pg" dirCopy "github.com/otiai10/copy" "go.uber.org/zap" "golang.org/x/exp/maps" @@ -58,7 +59,9 @@ type ChartRefDbReadService interface { FetchInfoOfChartConfiguredInApp(appId int) (*bean.ChartRefDto, error) ChartRefAutocomplete() ([]*bean.ChartRefAutocompleteDto, error) CheckChartExists(chartRefId int) error - ChartRefIdsCompatible(oldChartRefId int, newChartRefId int) (bool, string, string) + ChartRefIdsCompatible(oldChartRefId int, newChartRefId int) (bool, *bean.ChartRefSwitchRequest) + GetDeploymentStrategiesForChartRef(chartRefId int, pipelineOverride string) ([]bean.PipelineStrategy, error) + PerformChartSpecificPatchForSwitch(values json.RawMessage, chartChangeType *bean.ChartRefSwitchRequest) (json.RawMessage, error) } type CustomChartService interface { @@ -79,12 +82,13 @@ type ChartRefFileOpService interface { } type ChartRefServiceImpl struct { - logger *zap.SugaredLogger - chartRefRepository chartRepoRepository.ChartRefRepository - chartRefReadService read.ChartRefReadService - chartTemplateService util.ChartTemplateService - mergeUtil util.MergeUtil - chartRepository chartRepoRepository.ChartRepository + logger *zap.SugaredLogger + chartRefRepository chartRepoRepository.ChartRefRepository + chartRefReadService read.ChartRefReadService + chartTemplateService util.ChartTemplateService + mergeUtil util.MergeUtil + chartRepository chartRepoRepository.ChartRepository + globalStrategyMetadataRepository chartRepoRepository.GlobalStrategyMetadataChartRefMappingRepository } func NewChartRefServiceImpl(logger *zap.SugaredLogger, @@ -92,17 +96,20 @@ func NewChartRefServiceImpl(logger *zap.SugaredLogger, chartRefReadService read.ChartRefReadService, chartTemplateService util.ChartTemplateService, chartRepository chartRepoRepository.ChartRepository, - mergeUtil util.MergeUtil) *ChartRefServiceImpl { + mergeUtil util.MergeUtil, + globalStrategyMetadataRepository chartRepoRepository.GlobalStrategyMetadataChartRefMappingRepository, +) *ChartRefServiceImpl { // cache devtron reference charts list devtronChartList, _ := chartRefRepository.FetchAllNonUserUploadedChartInfo() setReservedChartList(devtronChartList) return &ChartRefServiceImpl{ - logger: logger, - chartRefRepository: chartRefRepository, - chartRefReadService: chartRefReadService, - chartTemplateService: chartTemplateService, - mergeUtil: mergeUtil, - chartRepository: chartRepository, + logger: logger, + chartRefRepository: chartRefRepository, + chartRefReadService: chartRefReadService, + chartTemplateService: chartTemplateService, + mergeUtil: mergeUtil, + chartRepository: chartRepository, + globalStrategyMetadataRepository: globalStrategyMetadataRepository, } } @@ -151,16 +158,19 @@ func (impl *ChartRefServiceImpl) GetAllChartMetadata() (map[string]bean.ChartRef return chartsMetadataMap, nil } -func (impl *ChartRefServiceImpl) ChartRefIdsCompatible(oldChartRefId int, newChartRefId int) (bool, string, string) { +func (impl *ChartRefServiceImpl) ChartRefIdsCompatible(oldChartRefId int, newChartRefId int) (bool, *bean.ChartRefSwitchRequest) { + chartChangeType := &bean.ChartRefSwitchRequest{} oldChart, err := impl.FindById(oldChartRefId) if err != nil { - return false, "", "" + return false, chartChangeType } newChart, err := impl.FindById(newChartRefId) if err != nil { - return false, "", "" + return false, chartChangeType } - return CheckCompatibility(oldChart.Name, newChart.Name), oldChart.Name, newChart.Name + chartChangeType.NewChartType = newChart.Name + chartChangeType.OldChartType = oldChart.Name + return CheckCompatibility(oldChart.Name, newChart.Name), chartChangeType } func (impl *ChartRefServiceImpl) FindById(chartRefId int) (*bean.ChartRefDto, error) { @@ -441,6 +451,7 @@ func (impl *ChartRefServiceImpl) CheckChartExists(chartRefId int) error { } return nil } + func (impl *ChartRefServiceImpl) GetAppOverrideForDefaultTemplate(chartRefId int) (map[string]interface{}, string, error) { err := impl.CheckChartExists(chartRefId) if err != nil { @@ -724,3 +735,60 @@ func setReservedChartList(devtronChartList []*chartRepoRepository.ChartRef) { } bean.ReservedChartRefNamesList = &reservedChartRefNamesList } + +func (impl *ChartRefServiceImpl) GetDeploymentStrategiesForChartRef(chartRefId int, pipelineOverride string) ([]bean.PipelineStrategy, error) { + // get global strategy for this chart + pipelineStrategies := make([]bean.PipelineStrategy, 0) + globalStrategies, err := impl.globalStrategyMetadataRepository.GetByChartRefId(chartRefId) + if err != nil && !errors.Is(err, pg.ErrNoRows) { + impl.logger.Errorw("error in getting global strategies", "chartRefId", chartRefId, "err", err) + return pipelineStrategies, err + } else if errors.Is(err, pg.ErrNoRows) { + impl.logger.Infow("no strategies configured for chart", "chartRefId", chartRefId) + return pipelineStrategies, nil + } + for _, globalStrategy := range globalStrategies { + pipelineStrategyJson, err := impl.filterDeploymentTemplate(globalStrategy.GlobalStrategyMetadata.Key, pipelineOverride) + if err != nil { + return pipelineStrategies, err + } + pipelineStrategy := bean.PipelineStrategy{ + DeploymentTemplate: globalStrategy.GlobalStrategyMetadata.Name, + Config: []byte(pipelineStrategyJson), + Default: globalStrategy.Default, + } + pipelineStrategies = append(pipelineStrategies, pipelineStrategy) + } + return pipelineStrategies, nil +} + +func (impl *ChartRefServiceImpl) filterDeploymentTemplate(strategyKey string, pipelineStrategiesJson string) (string, error) { + var pipelineStrategies bean.DeploymentType + err := json.Unmarshal([]byte(pipelineStrategiesJson), &pipelineStrategies) + if err != nil { + impl.logger.Errorw("error while unmarshal strategies", "err", err) + return "", err + } + strategyValue, ok := pipelineStrategies.Deployment.Strategy[strategyKey] + if !ok { + return "", fmt.Errorf("no deployment strategy found for %s", strategyKey) + } + strategy := make(map[string]interface{}) + strategy[strategyKey] = strategyValue.(map[string]interface{}) + pipelineStrategy := bean.DeploymentType{ + Deployment: bean.Deployment{ + Strategy: strategy, + }, + } + pipelineOverrideBytes, err := json.Marshal(pipelineStrategy) + if err != nil { + impl.logger.Errorw("error while marshal strategies", "err", err) + return "", err + } + pipelineStrategyJson := string(pipelineOverrideBytes) + return pipelineStrategyJson, nil +} + +func (impl *ChartRefServiceImpl) PerformChartSpecificPatchForSwitch(values json.RawMessage, chartChangeType *bean.ChartRefSwitchRequest) (json.RawMessage, error) { + return patchWinterSoldierConfig(values, chartChangeType.NewChartType) +} diff --git a/pkg/chart/ChartUtils.go b/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartUtils.go similarity index 79% rename from pkg/chart/ChartUtils.go rename to pkg/deployment/manifest/deploymentTemplate/chartRef/ChartUtils.go index 7794ac69d2..83b5ffaecb 100644 --- a/pkg/chart/ChartUtils.go +++ b/pkg/deployment/manifest/deploymentTemplate/chartRef/ChartUtils.go @@ -14,19 +14,19 @@ * limitations under the License. */ -package chart +package chartRef import ( "encoding/json" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" ) -func PatchWinterSoldierConfig(override json.RawMessage, newChartType string) (json.RawMessage, error) { +func patchWinterSoldierConfig(override json.RawMessage, newChartType string) (json.RawMessage, error) { var jsonMap map[string]json.RawMessage - if err := json.Unmarshal([]byte(override), &jsonMap); err != nil { + if err := json.Unmarshal(override, &jsonMap); err != nil { return override, err } - updatedJson, err := PatchWinterSoldierIfExists(newChartType, jsonMap) + updatedJson, err := patchWinterSoldierIfExists(newChartType, jsonMap) if err != nil { return override, err } @@ -38,13 +38,13 @@ func PatchWinterSoldierConfig(override json.RawMessage, newChartType string) (js return updatedOverride, nil } -func PatchWinterSoldierIfExists(newChartType string, jsonMap map[string]json.RawMessage) (map[string]json.RawMessage, error) { +func patchWinterSoldierIfExists(newChartType string, jsonMap map[string]json.RawMessage) (map[string]json.RawMessage, error) { winterSoldierConfig, found := jsonMap["winterSoldier"] if !found { return jsonMap, nil } var winterSoldierUnmarshalled map[string]json.RawMessage - if err := json.Unmarshal([]byte(winterSoldierConfig), &winterSoldierUnmarshalled); err != nil { + if err := json.Unmarshal(winterSoldierConfig, &winterSoldierUnmarshalled); err != nil { return jsonMap, err } @@ -66,7 +66,3 @@ func PatchWinterSoldierIfExists(newChartType string, jsonMap map[string]json.Raw jsonMap["winterSoldier"] = winterSoldierMarshalled return jsonMap, nil } - -//func IsFlaggerCanaryEnabled(override json.RawMessage) (bool, error) { -// -//} diff --git a/pkg/deployment/manifest/deploymentTemplate/chartRef/bean/bean.go b/pkg/deployment/manifest/deploymentTemplate/chartRef/bean/bean.go index a6c7866600..3002085224 100644 --- a/pkg/deployment/manifest/deploymentTemplate/chartRef/bean/bean.go +++ b/pkg/deployment/manifest/deploymentTemplate/chartRef/bean/bean.go @@ -17,29 +17,16 @@ package bean import ( + "encoding/json" + chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" "github.com/devtron-labs/devtron/pkg/sql" ) const ( - DeploymentChartType = "Deployment" - DeploymentChartNamePrefix = "deployment-chart_" - - WorkflowChartType = "workflow-chart" - WorkflowChartNamePrefix = "workflow-chart_" - - KnativeChartType = "Knative" - KnativeChartNamePrefix = "knative-chart_" - - StatefulSetChartType = "StatefulSet" - StatefulSetChartNamePrefix = "statefulset-chart_" - - JobAndCronJobType = "Job & CronJob" - JobAndCronJobNamePrefix = "cronjob-chart_" - - RolloutChartType = "Rollout Deployment" - RolloutChartNamePrefix = "reference-chart_" - ReferenceChart = "reference-chart" - RefChartDirPath = "scripts/devtron-reference-helm-charts" + DeploymentChartType = "Deployment" + RolloutChartType = "Rollout Deployment" + ReferenceChart = "reference-chart" + RefChartDirPath = "scripts/devtron-reference-helm-charts" ChartAlreadyExistsInternalError = "Chart exists already, try uploading another chart" ChartNameReservedInternalError = "Change the name of the chart and try uploading again" @@ -129,3 +116,26 @@ type ChartDto struct { IsUserUploaded bool `json:"isUserUploaded"` UploadedBy string `json:"uploadedBy"` } + +type ChartRefSwitchRequest struct { + NewChartType string + OldChartType string +} + +func (c *ChartRefSwitchRequest) IsFlaggerCanarySupported() bool { + return c.NewChartType == DeploymentChartType +} + +type DeploymentType struct { + Deployment Deployment `json:"deployment"` +} + +type Deployment struct { + Strategy map[string]interface{} `json:"strategy"` +} + +type PipelineStrategy struct { + DeploymentTemplate chartRepoRepository.DeploymentStrategy `json:"deploymentTemplate,omitempty"` // + Config json.RawMessage `json:"config"` + Default bool `json:"default"` +} diff --git a/pkg/deployment/manifest/deploymentTemplate/DeploymentTemplateValidationService.go b/pkg/deployment/manifest/deploymentTemplate/validator/DeploymentTemplateValidationService.go similarity index 53% rename from pkg/deployment/manifest/deploymentTemplate/DeploymentTemplateValidationService.go rename to pkg/deployment/manifest/deploymentTemplate/validator/DeploymentTemplateValidationService.go index f9ddcb7fa7..0f4b280e83 100644 --- a/pkg/deployment/manifest/deploymentTemplate/DeploymentTemplateValidationService.go +++ b/pkg/deployment/manifest/deploymentTemplate/validator/DeploymentTemplateValidationService.go @@ -14,15 +14,19 @@ * limitations under the License. */ -package deploymentTemplate +package validator import ( "context" "encoding/json" "errors" "fmt" + "github.com/devtron-labs/devtron/internal/util" + bean3 "github.com/devtron-labs/devtron/pkg/chart/bean" + "github.com/devtron-labs/devtron/pkg/deployment/manifest/deployedAppMetrics" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/bean" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef" + pipelineBean "github.com/devtron-labs/devtron/pkg/pipeline/bean" "github.com/devtron-labs/devtron/pkg/resourceQualifiers" "github.com/devtron-labs/devtron/pkg/variables" "github.com/devtron-labs/devtron/pkg/variables/parsers" @@ -30,26 +34,36 @@ import ( "github.com/xeipuuv/gojsonschema" "go.opentelemetry.io/otel" "go.uber.org/zap" + "net/http" ) type DeploymentTemplateValidationService interface { DeploymentTemplateValidate(ctx context.Context, template interface{}, chartRefId int, scope resourceQualifiers.Scope) (bool, error) FlaggerCanaryEnabled(values json.RawMessage) (bool, error) + ValidateChangeChartRefRequest(ctx context.Context, envConfigProperties *pipelineBean.EnvironmentProperties, request *bean3.ChartRefChangeRequest) (*pipelineBean.EnvironmentProperties, bool, error) + DeploymentTemplateValidationServiceEnt } type DeploymentTemplateValidationServiceImpl struct { - logger *zap.SugaredLogger - chartRefService chartRef.ChartRefService - scopedVariableManager variables.ScopedVariableManager + logger *zap.SugaredLogger + chartRefService chartRef.ChartRefService + scopedVariableManager variables.ScopedVariableManager + deployedAppMetricsService deployedAppMetrics.DeployedAppMetricsService + *DeploymentTemplateValidationServiceEntImpl } func NewDeploymentTemplateValidationServiceImpl(logger *zap.SugaredLogger, chartRefService chartRef.ChartRefService, - scopedVariableManager variables.ScopedVariableManager) *DeploymentTemplateValidationServiceImpl { + scopedVariableManager variables.ScopedVariableManager, + deployedAppMetricsService deployedAppMetrics.DeployedAppMetricsService, + deploymentTemplateValidationServiceEntImpl *DeploymentTemplateValidationServiceEntImpl, +) *DeploymentTemplateValidationServiceImpl { return &DeploymentTemplateValidationServiceImpl{ - logger: logger, - chartRefService: chartRefService, - scopedVariableManager: scopedVariableManager, + logger: logger, + chartRefService: chartRefService, + scopedVariableManager: scopedVariableManager, + deployedAppMetricsService: deployedAppMetricsService, + DeploymentTemplateValidationServiceEntImpl: deploymentTemplateValidationServiceEntImpl, } } @@ -141,3 +155,50 @@ func (impl *DeploymentTemplateValidationServiceImpl) FlaggerCanaryEnabled(values } return string(enabled) == bean.TrueFlag, nil } + +func (impl *DeploymentTemplateValidationServiceImpl) ValidateChangeChartRefRequest(ctx context.Context, envConfigProperties *pipelineBean.EnvironmentProperties, request *bean3.ChartRefChangeRequest) (*pipelineBean.EnvironmentProperties, bool, error) { + compatible, chartChangeType := impl.chartRefService.ChartRefIdsCompatible(envConfigProperties.ChartRefId, request.TargetChartRefId) + if !compatible { + errMsg := fmt.Sprintf("chart not compatible for appId: %d, envId: %d", request.AppId, request.EnvId) + return envConfigProperties, false, util.NewApiError(http.StatusUnprocessableEntity, errMsg, errMsg) + } + if !chartChangeType.IsFlaggerCanarySupported() { + enabled, err := impl.FlaggerCanaryEnabled(envConfigProperties.EnvOverrideValues) + if err != nil { + impl.logger.Errorw("error in checking flaggerCanary, ChangeChartRef", "err", err, "payload", envConfigProperties.EnvOverrideValues) + return envConfigProperties, false, err + } else if enabled { + impl.logger.Errorw("rollout charts do not support flaggerCanary, ChangeChartRef", "templateValues", envConfigProperties.EnvOverrideValues) + errMsg := fmt.Sprintf("%q charts do not support flaggerCanary", chartChangeType.NewChartType) + return envConfigProperties, false, util.NewApiError(http.StatusUnprocessableEntity, errMsg, errMsg) + } + } + var err error + envConfigProperties.EnvOverrideValues, err = impl.chartRefService.PerformChartSpecificPatchForSwitch(envConfigProperties.EnvOverrideValues, chartChangeType) + if err != nil { + impl.logger.Errorw("error in chart specific patch operations, ValidateChangeChartRefRequest", "err", err, "payload", request) + return envConfigProperties, false, err + } + envMetrics, err := impl.deployedAppMetricsService.GetMetricsFlagByAppIdAndEnvId(request.AppId, request.EnvId) + if err != nil { + impl.logger.Errorw("could not find envMetrics for, ChangeChartRef", "err", err, "payload", request) + errMsg := fmt.Sprintf("could not find envMetrics for appId: %d, envId: %d", request.AppId, request.EnvId) + return envConfigProperties, false, util.NewApiError(http.StatusBadRequest, errMsg, err.Error()) + } + envConfigProperties.ChartRefId = request.TargetChartRefId + envConfigProperties.EnvironmentId = request.EnvId + envConfigProperties.AppMetrics = &envMetrics + // VARIABLE_RESOLVE + scope := resourceQualifiers.Scope{ + AppId: request.AppId, + EnvId: request.EnvId, + ClusterId: envConfigProperties.ClusterId, + } + validate, err2 := impl.DeploymentTemplateValidate(ctx, envConfigProperties.EnvOverrideValues, envConfigProperties.ChartRefId, scope) + if !validate { + impl.logger.Errorw("validation err, UpdateAppOverride", "err", err2, "payload", request) + errMsg := fmt.Sprintf("template schema validation error for appId: %d, envId: %d", request.AppId, request.EnvId) + return envConfigProperties, envMetrics, util.NewApiError(http.StatusBadRequest, errMsg, err2.Error()) + } + return envConfigProperties, envMetrics, nil +} diff --git a/pkg/deployment/manifest/deploymentTemplate/validator/DeploymentTemplateValidationService_ent.go b/pkg/deployment/manifest/deploymentTemplate/validator/DeploymentTemplateValidationService_ent.go new file mode 100644 index 0000000000..8a9cc4b0f5 --- /dev/null +++ b/pkg/deployment/manifest/deploymentTemplate/validator/DeploymentTemplateValidationService_ent.go @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020-2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package validator + +type DeploymentTemplateValidationServiceEnt interface { +} + +type DeploymentTemplateValidationServiceEntImpl struct { +} + +func NewDeploymentTemplateValidationServiceEntImpl() *DeploymentTemplateValidationServiceEntImpl { + return &DeploymentTemplateValidationServiceEntImpl{} +} diff --git a/pkg/deployment/manifest/deploymentTemplate/wire_deploymentTemplate.go b/pkg/deployment/manifest/deploymentTemplate/wire_deploymentTemplate.go index f8df37c0c0..cd793b9bfd 100644 --- a/pkg/deployment/manifest/deploymentTemplate/wire_deploymentTemplate.go +++ b/pkg/deployment/manifest/deploymentTemplate/wire_deploymentTemplate.go @@ -20,6 +20,7 @@ import ( "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef" chartRefRead "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/read" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/read" + "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/validator" "github.com/google/wire" ) @@ -30,8 +31,9 @@ var DeploymentTemplateWireSet = wire.NewSet( read.NewEnvConfigOverrideReadServiceImpl, wire.Bind(new(read.EnvConfigOverrideService), new(*read.EnvConfigOverrideReadServiceImpl)), - NewDeploymentTemplateValidationServiceImpl, - wire.Bind(new(DeploymentTemplateValidationService), new(*DeploymentTemplateValidationServiceImpl)), + validator.NewDeploymentTemplateValidationServiceEntImpl, + validator.NewDeploymentTemplateValidationServiceImpl, + wire.Bind(new(validator.DeploymentTemplateValidationService), new(*validator.DeploymentTemplateValidationServiceImpl)), chartRefRead.NewChartRefReadServiceImpl, wire.Bind(new(chartRefRead.ChartRefReadService), new(*chartRefRead.ChartRefReadServiceImpl)), diff --git a/pkg/deployment/manifest/helper/helper.go b/pkg/deployment/manifest/helper/helper.go index dcff0865c1..1143a448ed 100644 --- a/pkg/deployment/manifest/helper/helper.go +++ b/pkg/deployment/manifest/helper/helper.go @@ -167,7 +167,7 @@ func NewMergedCmAndCsJsonV2Request(overrideRequest *bean.ValuesOverrideRequest, func NewMergedCmAndCsJsonV2Response() *bean3.MergedCmAndCsJsonV2Response { return &bean3.MergedCmAndCsJsonV2Response{ - MergedJson: []byte("{}"), + MergedJson: util4.GetEmptyJSON(), ExternalCsList: make([]string, 0), ExternalCmList: make([]string, 0), } diff --git a/pkg/generateManifest/DeploymentTemplateService.go b/pkg/generateManifest/DeploymentTemplateService.go index eaab4bc77d..cb986b7261 100644 --- a/pkg/generateManifest/DeploymentTemplateService.go +++ b/pkg/generateManifest/DeploymentTemplateService.go @@ -22,7 +22,7 @@ import ( "github.com/caarlos0/env" "github.com/devtron-labs/common-lib/utils/k8s" "github.com/devtron-labs/devtron/api/helm-app/gRPC" - read2 "github.com/devtron-labs/devtron/api/helm-app/service/read" + read3 "github.com/devtron-labs/devtron/api/helm-app/service/read" openapi2 "github.com/devtron-labs/devtron/api/openapi/openapiClient" "github.com/devtron-labs/devtron/internal/sql/repository" appRepository "github.com/devtron-labs/devtron/internal/sql/repository/app" @@ -31,10 +31,11 @@ import ( "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/app" "github.com/devtron-labs/devtron/pkg/chart" + read2 "github.com/devtron-labs/devtron/pkg/chart/read" chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" clusterBean "github.com/devtron-labs/devtron/pkg/cluster/bean" repository3 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" - read3 "github.com/devtron-labs/devtron/pkg/deployment/common/read" + cdConfigRead "github.com/devtron-labs/devtron/pkg/deployment/common/read" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/read" bean2 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/bean" @@ -72,9 +73,10 @@ type DeploymentTemplateService interface { type DeploymentTemplateServiceImpl struct { Logger *zap.SugaredLogger chartService chart.ChartService + chartReadService read2.ChartReadService appListingService app.AppListingService deploymentTemplateRepository repository.DeploymentTemplateRepository - helmAppReadService read2.HelmAppReadService + helmAppReadService read3.HelmAppReadService chartTemplateServiceImpl util.ChartTemplateService K8sUtil *k8s.K8sServiceImpl helmAppClient gRPC.HelmAppClient @@ -89,7 +91,7 @@ type DeploymentTemplateServiceImpl struct { restartWorkloadConfig *RestartWorkloadConfig mergeUtil *util.MergeUtil deploymentTemplateHistoryReadService read.DeploymentTemplateHistoryReadService - deploymentConfigReadService read3.DeploymentConfigReadService + deploymentConfigReadService cdConfigRead.DeploymentConfigReadService } func GetRestartWorkloadConfig() (*RestartWorkloadConfig, error) { @@ -99,9 +101,10 @@ func GetRestartWorkloadConfig() (*RestartWorkloadConfig, error) { } func NewDeploymentTemplateServiceImpl(Logger *zap.SugaredLogger, chartService chart.ChartService, + chartReadService read2.ChartReadService, appListingService app.AppListingService, deploymentTemplateRepository repository.DeploymentTemplateRepository, - helmAppReadService read2.HelmAppReadService, + helmAppReadService read3.HelmAppReadService, chartTemplateServiceImpl util.ChartTemplateService, helmAppClient gRPC.HelmAppClient, K8sUtil *k8s.K8sServiceImpl, @@ -115,11 +118,12 @@ func NewDeploymentTemplateServiceImpl(Logger *zap.SugaredLogger, chartService ch pipelineRepository pipelineConfig.PipelineRepository, mergeUtil *util.MergeUtil, deploymentTemplateHistoryReadService read.DeploymentTemplateHistoryReadService, - deploymentConfigReadService read3.DeploymentConfigReadService, + deploymentConfigReadService cdConfigRead.DeploymentConfigReadService, ) (*DeploymentTemplateServiceImpl, error) { deploymentTemplateServiceImpl := &DeploymentTemplateServiceImpl{ Logger: Logger, chartService: chartService, + chartReadService: chartReadService, appListingService: appListingService, deploymentTemplateRepository: deploymentTemplateRepository, helmAppReadService: helmAppReadService, @@ -535,7 +539,7 @@ func (impl DeploymentTemplateServiceImpl) patchReleaseAttributes(request *Deploy return } - chartDto, err := impl.chartService.GetByAppIdAndChartRefId(request.AppId, request.ChartRefId) + chartDto, err := impl.chartReadService.GetByAppIdAndChartRefId(request.AppId, request.ChartRefId) if err != nil { impl.Logger.Errorw("error in getting the chart using appId and chartRefId", "appId", request.AppId, "chartRefId", request.ChartRefId, "err", err) return diff --git a/pkg/pipeline/DeploymentPipelineConfigService.go b/pkg/pipeline/DeploymentPipelineConfigService.go index 82347de4fc..caf37f0e51 100644 --- a/pkg/pipeline/DeploymentPipelineConfigService.go +++ b/pkg/pipeline/DeploymentPipelineConfigService.go @@ -2471,11 +2471,11 @@ func (impl *CdPipelineConfigServiceImpl) parseEnvOverrideCreateRequestForExterna chartCreateRequest := bean6.TemplateRequest{ AppId: app.Id, ChartRefId: chartRef.Id, - ValuesOverride: []byte("{}"), + ValuesOverride: globalUtil.GetEmptyJSON(), UserId: userId, IsAppMetricsEnabled: false, } - _, err = impl.chartService.CreateChartFromEnvOverride(chartCreateRequest, context.Background()) + _, err = impl.chartService.CreateChartFromEnvOverride(context.Background(), chartCreateRequest) if err != nil { impl.logger.Errorw("error in creating chart from env override", "appId", app.Id, "chartRefId", chartRef.Id, "err", err) return nil, err @@ -2552,7 +2552,8 @@ func (impl *CdPipelineConfigServiceImpl) extractHelmChartForExternalArgoApp(repo } func (impl *CdPipelineConfigServiceImpl) updateCdPipeline(ctx context.Context, pipeline *bean.CDPipelineConfigObject, userID int32) (err error) { - + _, span := otel.Tracer("orchestrator").Start(ctx, "CdPipelineConfigServiceImpl.updateCdPipeline") + defer span.End() if len(pipeline.PreStage.Config) > 0 && !strings.Contains(pipeline.PreStage.Config, "beforeStages") { err = &util.ApiError{ HttpStatusCode: http.StatusBadRequest, @@ -2598,7 +2599,7 @@ func (impl *CdPipelineConfigServiceImpl) updateCdPipeline(ctx context.Context, p if notFound { //delete from db - err := impl.pipelineConfigRepository.Delete(oldItem, tx) + err := impl.pipelineConfigRepository.MarkAsDeleted(oldItem, userID, tx) if err != nil { impl.logger.Errorw("error in delete pipeline strategies", "err", err) return fmt.Errorf("error in delete pipeline strategies") diff --git a/pkg/pipeline/DevtronAppCMCSService.go b/pkg/pipeline/DevtronAppCMCSService.go index 4336cebbcf..5ff8680855 100644 --- a/pkg/pipeline/DevtronAppCMCSService.go +++ b/pkg/pipeline/DevtronAppCMCSService.go @@ -25,7 +25,7 @@ import ( type DevtronAppCMCSService interface { //FetchConfigmapSecretsForCdStages : Delegating the request to appService for fetching cm/cs - FetchConfigmapSecretsForCdStages(appId, envId, cdPipelineId int) (ConfigMapSecretsResponse, error) + FetchConfigmapSecretsForCdStages(appId, envId int) (ConfigMapSecretsResponse, error) } type DevtronAppCMCSServiceImpl struct { @@ -46,14 +46,14 @@ func NewDevtronAppCMCSServiceImpl( } } -func (impl *DevtronAppCMCSServiceImpl) FetchConfigmapSecretsForCdStages(appId, envId, cdPipelineId int) (ConfigMapSecretsResponse, error) { - configMapSecrets, err := impl.appService.GetConfigMapAndSecretJson(appId, envId, cdPipelineId) +func (impl *DevtronAppCMCSServiceImpl) FetchConfigmapSecretsForCdStages(appId, envId int) (ConfigMapSecretsResponse, error) { + configMapSecrets, err := impl.appService.GetConfigMapAndSecretJson(appId, envId) if err != nil { impl.logger.Errorw("error while fetching config secrets ", "err", err) return ConfigMapSecretsResponse{}, err } existingConfigMapSecrets := ConfigMapSecretsResponse{} - err = json.Unmarshal([]byte(configMapSecrets), &existingConfigMapSecrets) + err = json.Unmarshal(configMapSecrets, &existingConfigMapSecrets) if err != nil { impl.logger.Error(err) return ConfigMapSecretsResponse{}, err diff --git a/pkg/pipeline/DevtronAppStrategyService.go b/pkg/pipeline/DevtronAppStrategyService.go index 06b1f8651b..b126f16b47 100644 --- a/pkg/pipeline/DevtronAppStrategyService.go +++ b/pkg/pipeline/DevtronAppStrategyService.go @@ -17,9 +17,11 @@ package pipeline import ( - "encoding/json" + "errors" "fmt" chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" + "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef" + "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" "github.com/go-pg/pg" "go.uber.org/zap" ) @@ -30,7 +32,7 @@ type DevtronAppStrategyService interface { // FetchDefaultCDPipelineStrategy : // TODO: uncomment this after code has been refactored as this function doesnt contain any logic to fetch strategy - FetchDefaultCDPipelineStrategy(appId int, envId int) (PipelineStrategy, error) + FetchDefaultCDPipelineStrategy(appId int, envId int) (bean.PipelineStrategy, error) } type DevtronAppStrategyServiceImpl struct { @@ -38,8 +40,8 @@ type DevtronAppStrategyServiceImpl struct { chartRepository chartRepoRepository.ChartRepository globalStrategyMetadataChartRefMappingRepository chartRepoRepository.GlobalStrategyMetadataChartRefMappingRepository ciCdPipelineOrchestrator CiCdPipelineOrchestrator - - cdPipelineConfigService CdPipelineConfigService + cdPipelineConfigService CdPipelineConfigService + chartRefService chartRef.ChartRefService } func NewDevtronAppStrategyServiceImpl( @@ -47,54 +49,40 @@ func NewDevtronAppStrategyServiceImpl( chartRepository chartRepoRepository.ChartRepository, globalStrategyMetadataChartRefMappingRepository chartRepoRepository.GlobalStrategyMetadataChartRefMappingRepository, ciCdPipelineOrchestrator CiCdPipelineOrchestrator, - cdPipelineConfigService CdPipelineConfigService) *DevtronAppStrategyServiceImpl { + cdPipelineConfigService CdPipelineConfigService, + chartRefService chartRef.ChartRefService, +) *DevtronAppStrategyServiceImpl { return &DevtronAppStrategyServiceImpl{ logger: logger, chartRepository: chartRepository, globalStrategyMetadataChartRefMappingRepository: globalStrategyMetadataChartRefMappingRepository, ciCdPipelineOrchestrator: ciCdPipelineOrchestrator, cdPipelineConfigService: cdPipelineConfigService, + chartRefService: chartRefService, } } func (impl *DevtronAppStrategyServiceImpl) FetchCDPipelineStrategy(appId int) (PipelineStrategiesResponse, error) { pipelineStrategiesResponse := PipelineStrategiesResponse{} chart, err := impl.chartRepository.FindLatestChartForAppByAppId(appId) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorf("invalid state", "err", err, "appId", appId) + if err != nil && !errors.Is(err, pg.ErrNoRows) { + impl.logger.Errorw("error in fetching chart for app", "appId", appId, "err", err) return pipelineStrategiesResponse, err } if chart.Id == 0 { return pipelineStrategiesResponse, fmt.Errorf("no chart configured") } - - //get global strategy for this chart - globalStrategies, err := impl.globalStrategyMetadataChartRefMappingRepository.GetByChartRefId(chart.ChartRefId) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in getting global strategies", "err", err) + pipelineStrategies, err := impl.chartRefService.GetDeploymentStrategiesForChartRef(chart.ChartRefId, chart.PipelineOverride) + if err != nil { + impl.logger.Errorw("error in fetching deployment strategies for chart ref", "chartRefId", chart.ChartRefId, "err", err) return pipelineStrategiesResponse, err - } else if err == pg.ErrNoRows { - impl.logger.Infow("no strategies configured for chart", "chartRefId", chart.ChartRefId) - return pipelineStrategiesResponse, nil - } - pipelineOverride := chart.PipelineOverride - for _, globalStrategy := range globalStrategies { - pipelineStrategyJson, err := impl.filterDeploymentTemplate(globalStrategy.GlobalStrategyMetadata.Key, pipelineOverride) - if err != nil { - return pipelineStrategiesResponse, err - } - pipelineStrategy := PipelineStrategy{ - DeploymentTemplate: globalStrategy.GlobalStrategyMetadata.Name, - Config: []byte(pipelineStrategyJson), - } - pipelineStrategy.Default = globalStrategy.Default - pipelineStrategiesResponse.PipelineStrategy = append(pipelineStrategiesResponse.PipelineStrategy, pipelineStrategy) } + pipelineStrategiesResponse.PipelineStrategy = pipelineStrategies return pipelineStrategiesResponse, nil } -func (impl *DevtronAppStrategyServiceImpl) FetchDefaultCDPipelineStrategy(appId int, envId int) (PipelineStrategy, error) { - pipelineStrategy := PipelineStrategy{} +func (impl *DevtronAppStrategyServiceImpl) FetchDefaultCDPipelineStrategy(appId int, envId int) (bean.PipelineStrategy, error) { + pipelineStrategy := bean.PipelineStrategy{} cdPipelines, err := impl.ciCdPipelineOrchestrator.GetCdPipelinesForAppAndEnv(appId, envId) if err != nil || (cdPipelines.Pipelines) == nil || len(cdPipelines.Pipelines) == 0 { return pipelineStrategy, err @@ -109,29 +97,3 @@ func (impl *DevtronAppStrategyServiceImpl) FetchDefaultCDPipelineStrategy(appId pipelineStrategy.Default = true return pipelineStrategy, nil } - -func (impl *DevtronAppStrategyServiceImpl) filterDeploymentTemplate(strategyKey string, pipelineStrategiesJson string) (string, error) { - var pipelineStrategies DeploymentType - err := json.Unmarshal([]byte(pipelineStrategiesJson), &pipelineStrategies) - if err != nil { - impl.logger.Errorw("error while unmarshal strategies", "err", err) - return "", err - } - if pipelineStrategies.Deployment.Strategy[strategyKey] == nil { - return "", fmt.Errorf("no deployment strategy found for %s", strategyKey) - } - strategy := make(map[string]interface{}) - strategy[strategyKey] = pipelineStrategies.Deployment.Strategy[strategyKey].(map[string]interface{}) - pipelineStrategy := DeploymentType{ - Deployment: Deployment{ - Strategy: strategy, - }, - } - pipelineOverrideBytes, err := json.Marshal(pipelineStrategy) - if err != nil { - impl.logger.Errorw("error while marshal strategies", "err", err) - return "", err - } - pipelineStrategyJson := string(pipelineOverrideBytes) - return pipelineStrategyJson, nil -} diff --git a/pkg/pipeline/PipelineBuilder.go b/pkg/pipeline/PipelineBuilder.go index 336dfd8cba..015980d199 100644 --- a/pkg/pipeline/PipelineBuilder.go +++ b/pkg/pipeline/PipelineBuilder.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/devtron-labs/devtron/internal/sql/constants" "github.com/devtron-labs/devtron/pkg/build/git/gitMaterial/read" + chartRefBean "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/bean" "net/url" "strings" "time" @@ -202,14 +203,6 @@ func getPatchMessage(err error) string { return "" } -type DeploymentType struct { - Deployment Deployment `json:"deployment"` -} - -type Deployment struct { - Strategy map[string]interface{} `json:"strategy"` -} - type ConfigMapSecretsResponse struct { Maps []bean2.ConfigSecretMap `json:"maps"` Secrets []bean2.ConfigSecretMap `json:"secrets"` @@ -277,12 +270,7 @@ type AppBean struct { } type PipelineStrategiesResponse struct { - PipelineStrategy []PipelineStrategy `json:"pipelineStrategy"` -} -type PipelineStrategy struct { - DeploymentTemplate chartRepoRepository.DeploymentStrategy `json:"deploymentTemplate,omitempty"` // - Config json.RawMessage `json:"config"` - Default bool `json:"default"` + PipelineStrategy []chartRefBean.PipelineStrategy `json:"pipelineStrategy"` } func CheckAppReleaseNotExist(err error) bool { diff --git a/pkg/pipeline/PropertiesConfig.go b/pkg/pipeline/PropertiesConfig.go index ec3dc93945..65a9de1398 100644 --- a/pkg/pipeline/PropertiesConfig.go +++ b/pkg/pipeline/PropertiesConfig.go @@ -36,6 +36,8 @@ import ( "github.com/devtron-labs/devtron/pkg/pipeline/bean" "github.com/devtron-labs/devtron/pkg/variables" repository5 "github.com/devtron-labs/devtron/pkg/variables/repository" + globalUtil "github.com/devtron-labs/devtron/util" + "go.opentelemetry.io/otel" "net/http" "time" @@ -64,6 +66,9 @@ type PropertiesConfigService interface { CreateEnvironmentPropertiesWithNamespace(appId int, propertiesRequest *bean.EnvironmentProperties) (*bean.EnvironmentProperties, error) FetchEnvProperties(appId, envId, chartRefId int) (*bean4.EnvConfigOverride, error) + ChangeChartRefForEnvConfigOverride(ctx context.Context, request *bean3.ChartRefChangeRequest, userId int32) (*bean.EnvironmentProperties, error) + + PropertiesConfigServiceEnt } type PropertiesConfigServiceImpl struct { logger *zap.SugaredLogger @@ -103,7 +108,7 @@ func NewPropertiesConfigServiceImpl(logger *zap.SugaredLogger, } -func (impl PropertiesConfigServiceImpl) GetEnvironmentProperties(appId, environmentId int, chartRefId int) (environmentPropertiesResponse *bean.EnvironmentPropertiesResponse, err error) { +func (impl *PropertiesConfigServiceImpl) GetEnvironmentProperties(appId, environmentId int, chartRefId int) (environmentPropertiesResponse *bean.EnvironmentPropertiesResponse, err error) { environmentPropertiesResponse = &bean.EnvironmentPropertiesResponse{} env, err := impl.environmentRepository.FindById(environmentId) if err != nil { @@ -217,11 +222,11 @@ func (impl PropertiesConfigServiceImpl) GetEnvironmentProperties(appId, environm return environmentPropertiesResponse, nil } -func (impl PropertiesConfigServiceImpl) FetchEnvProperties(appId, envId, chartRefId int) (*bean4.EnvConfigOverride, error) { +func (impl *PropertiesConfigServiceImpl) FetchEnvProperties(appId, envId, chartRefId int) (*bean4.EnvConfigOverride, error) { return impl.envConfigOverrideReadService.GetByAppIdEnvIdAndChartRefId(appId, envId, chartRefId) } -func (impl PropertiesConfigServiceImpl) CreateEnvironmentPropertiesAndBaseIfNeeded(ctx context.Context, appId int, environmentProperties *bean.EnvironmentProperties) (*bean.EnvironmentProperties, error) { +func (impl *PropertiesConfigServiceImpl) CreateEnvironmentPropertiesAndBaseIfNeeded(ctx context.Context, appId int, environmentProperties *bean.EnvironmentProperties) (*bean.EnvironmentProperties, error) { createResp, err := impl.CreateEnvironmentProperties(appId, environmentProperties) if err != nil { if err.Error() == bean5.NOCHARTEXIST { @@ -232,11 +237,11 @@ func (impl PropertiesConfigServiceImpl) CreateEnvironmentPropertiesAndBaseIfNeed templateRequest := bean3.TemplateRequest{ AppId: appId, ChartRefId: environmentProperties.ChartRefId, - ValuesOverride: []byte("{}"), + ValuesOverride: globalUtil.GetEmptyJSON(), UserId: environmentProperties.UserId, IsAppMetricsEnabled: appMetrics, } - _, err = impl.chartService.CreateChartFromEnvOverride(templateRequest, ctx) + _, err = impl.chartService.CreateChartFromEnvOverride(ctx, templateRequest) if err != nil { impl.logger.Errorw("service err, EnvConfigOverrideCreate", "err", err, "payload", environmentProperties) return nil, err @@ -254,7 +259,7 @@ func (impl PropertiesConfigServiceImpl) CreateEnvironmentPropertiesAndBaseIfNeed return createResp, nil } -func (impl PropertiesConfigServiceImpl) CreateEnvironmentProperties(appId int, environmentProperties *bean.EnvironmentProperties) (*bean.EnvironmentProperties, error) { +func (impl *PropertiesConfigServiceImpl) CreateEnvironmentProperties(appId int, environmentProperties *bean.EnvironmentProperties) (*bean.EnvironmentProperties, error) { chart, err := impl.chartRepo.FindChartByAppIdAndRefId(appId, environmentProperties.ChartRefId) if err != nil && !errors2.Is(err, pg.ErrNoRows) { return nil, err @@ -327,7 +332,7 @@ func (impl PropertiesConfigServiceImpl) CreateEnvironmentProperties(appId int, e return environmentProperties, nil } -func (impl PropertiesConfigServiceImpl) UpdateEnvironmentProperties(appId int, propertiesRequest *bean.EnvironmentProperties, userId int32) (*bean.EnvironmentProperties, error) { +func (impl *PropertiesConfigServiceImpl) UpdateEnvironmentProperties(appId int, propertiesRequest *bean.EnvironmentProperties, userId int32) (*bean.EnvironmentProperties, error) { //check if exists oldEnvOverride, err := impl.envConfigOverrideReadService.GetByIdIncludingInactive(propertiesRequest.Id) if err != nil { @@ -437,7 +442,7 @@ func (impl PropertiesConfigServiceImpl) UpdateEnvironmentProperties(appId int, p return propertiesRequest, err } -func (impl PropertiesConfigServiceImpl) CreateIfRequired(request *bean.EnvironmentOverrideCreateInternalDTO, tx *pg.Tx) (*bean4.EnvConfigOverride, bool, error) { +func (impl *PropertiesConfigServiceImpl) CreateIfRequired(request *bean.EnvironmentOverrideCreateInternalDTO, tx *pg.Tx) (*bean4.EnvConfigOverride, bool, error) { chart := request.Chart environmentId := request.EnvironmentId @@ -564,7 +569,7 @@ func (impl PropertiesConfigServiceImpl) CreateIfRequired(request *bean.Environme return envOverride, isAppMetricsEnabled, nil } -func (impl PropertiesConfigServiceImpl) GetEnvironmentPropertiesById(envId int) ([]bean.EnvironmentProperties, error) { +func (impl *PropertiesConfigServiceImpl) GetEnvironmentPropertiesById(envId int) ([]bean.EnvironmentProperties, error) { var envProperties []bean.EnvironmentProperties envOverrides, err := impl.envConfigOverrideReadService.GetByEnvironment(envId) @@ -586,7 +591,7 @@ func (impl PropertiesConfigServiceImpl) GetEnvironmentPropertiesById(envId int) return envProperties, nil } -func (impl PropertiesConfigServiceImpl) GetAppIdByChartEnvId(chartEnvId int) (*bean4.EnvConfigOverride, error) { +func (impl *PropertiesConfigServiceImpl) GetAppIdByChartEnvId(chartEnvId int) (*bean4.EnvConfigOverride, error) { envOverride, err := impl.envConfigOverrideReadService.GetByIdIncludingInactive(chartEnvId) if err != nil { impl.logger.Error("error fetching override config", "err", err) @@ -595,7 +600,7 @@ func (impl PropertiesConfigServiceImpl) GetAppIdByChartEnvId(chartEnvId int) (*b return envOverride, nil } -func (impl PropertiesConfigServiceImpl) GetLatestEnvironmentProperties(appId, environmentId int) (environmentProperties *bean.EnvironmentProperties, err error) { +func (impl *PropertiesConfigServiceImpl) GetLatestEnvironmentProperties(appId, environmentId int) (environmentProperties *bean.EnvironmentProperties, err error) { env, err := impl.environmentRepository.FindById(environmentId) if err != nil { return nil, err @@ -609,34 +614,34 @@ func (impl PropertiesConfigServiceImpl) GetLatestEnvironmentProperties(appId, en //return nil, errors.New("No env config exists with tag latest for given appId and envId") impl.logger.Warnw("No env config exists with tag latest for given appId and envId", "envId", environmentId) } else { - r := json.RawMessage{} + r := json.RawMessage("{}") err = r.UnmarshalJSON([]byte(envOverride.EnvOverrideValues)) if err != nil { return nil, err } - environmentProperties = &bean.EnvironmentProperties{ Id: envOverride.Id, - EnvOverrideValues: r, Status: envOverride.Status, + EnvOverrideValues: r, ManualReviewed: envOverride.ManualReviewed, Active: envOverride.Active, Namespace: env.Namespace, + Description: env.Description, EnvironmentId: environmentId, EnvironmentName: env.Name, Latest: envOverride.Latest, + ChartRefId: envOverride.Chart.ChartRefId, IsOverride: envOverride.IsOverride, IsBasicViewLocked: envOverride.IsBasicViewLocked, CurrentViewEditor: envOverride.CurrentViewEditor, - ChartRefId: envOverride.Chart.ChartRefId, + MergeStrategy: envOverride.MergeStrategy, ClusterId: env.ClusterId, } } - return environmentProperties, nil } -func (impl PropertiesConfigServiceImpl) ResetEnvironmentProperties(id int, userId int32) (bool, error) { +func (impl *PropertiesConfigServiceImpl) ResetEnvironmentProperties(id int, userId int32) (bool, error) { envOverride, err := impl.envConfigOverrideReadService.GetByIdIncludingInactive(id) if err != nil { return false, err @@ -676,15 +681,15 @@ func (impl PropertiesConfigServiceImpl) ResetEnvironmentProperties(id int, userI return true, nil } -func (impl PropertiesConfigServiceImpl) CreateEnvironmentPropertiesWithNamespace(appId int, environmentProperties *bean.EnvironmentProperties) (*bean.EnvironmentProperties, error) { +func (impl *PropertiesConfigServiceImpl) CreateEnvironmentPropertiesWithNamespace(appId int, environmentProperties *bean.EnvironmentProperties) (*bean.EnvironmentProperties, error) { chart, err := impl.chartRepo.FindChartByAppIdAndRefId(appId, environmentProperties.ChartRefId) - if err != nil && pg.ErrNoRows != err { + if err != nil && !errors2.Is(err, pg.ErrNoRows) { return nil, err } - if pg.ErrNoRows == err { + if errors2.Is(err, pg.ErrNoRows) { impl.logger.Warnw("no chart found this ref id", "refId", environmentProperties.ChartRefId) chart, err = impl.chartRepo.FindLatestChartForAppByAppId(appId) - if err != nil && pg.ErrNoRows != err { + if err != nil && !errors2.Is(err, pg.ErrNoRows) { return nil, err } } @@ -753,3 +758,57 @@ func (impl PropertiesConfigServiceImpl) CreateEnvironmentPropertiesWithNamespace } return environmentProperties, nil } + +func (impl *PropertiesConfigServiceImpl) ChangeChartRefForEnvConfigOverride(ctx context.Context, request *bean3.ChartRefChangeRequest, userId int32) (*bean.EnvironmentProperties, error) { + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "PropertiesConfigServiceImpl.ChangeChartRefForEnvConfigOverride") + defer span.End() + envConfigPropertiesOld, err := impl.FetchEnvProperties(request.AppId, request.EnvId, request.TargetChartRefId) + if err != nil && !errors2.Is(err, pg.ErrNoRows) { + impl.logger.Errorw("service err, ChangeChartRef", "err", err, "payload", request) + return nil, fmt.Errorf("could not fetch env properties. error: %v", err) + } else if errors2.Is(err, pg.ErrNoRows) { + createResp, err := impl.createEnvConfigOverrideWithChart(newCtx, request, userId) + if err != nil { + impl.logger.Errorw("service err, ChangeChartRef", "err", err, "payload", request) + return nil, err + } + return createResp, nil + } + envConfigProperties := request.EnvConfigProperties + envConfigProperties.Id = envConfigPropertiesOld.Id + createResp, err := impl.UpdateEnvironmentProperties(request.AppId, envConfigProperties, userId) + if err != nil { + impl.logger.Errorw("service err, EnvConfigOverrideUpdate", "err", err, "payload", envConfigProperties) + return nil, fmt.Errorf("could not update env override, error: %v", err) + } + return createResp, nil +} + +func (impl *PropertiesConfigServiceImpl) createEnvConfigOverrideWithChart(ctx context.Context, request *bean3.ChartRefChangeRequest, userId int32) (*bean.EnvironmentProperties, error) { + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "PropertiesConfigServiceImpl.createEnvConfigOverrideWithChart") + defer span.End() + createResp, err := impl.CreateEnvironmentProperties(request.AppId, request.EnvConfigProperties) + if err != nil && err.Error() != bean5.NOCHARTEXIST { + impl.logger.Errorw("service err, EnvConfigOverrideCreate", "err", err, "payload", request) + return nil, fmt.Errorf("could not create env override, error: %v", err) + } else if err != nil && err.Error() == bean5.NOCHARTEXIST { + appMetrics := false + if request.EnvConfigProperties.AppMetrics != nil { + appMetrics = request.EnvMetrics + } + templateRequest := bean3.TemplateRequest{ + AppId: request.AppId, + ChartRefId: request.TargetChartRefId, + ValuesOverride: globalUtil.GetEmptyJSON(), + UserId: userId, + IsAppMetricsEnabled: appMetrics, + } + _, err := impl.chartService.CreateChartFromEnvOverride(newCtx, templateRequest) + if err != nil { + impl.logger.Errorw("service err, CreateChartFromEnvOverride", "err", err, "payload", request) + return nil, fmt.Errorf("could not create chart from env override, error: %v", err) + } + return impl.CreateEnvironmentProperties(request.AppId, request.EnvConfigProperties) + } + return createResp, nil +} diff --git a/pkg/pipeline/PropertiesConfig_ent.go b/pkg/pipeline/PropertiesConfig_ent.go new file mode 100644 index 0000000000..a2add41861 --- /dev/null +++ b/pkg/pipeline/PropertiesConfig_ent.go @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020-2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package pipeline + +type PropertiesConfigServiceEnt interface { +} diff --git a/util/JsonHelper.go b/util/JsonHelper.go index 90ec099f10..a10e50d377 100644 --- a/util/JsonHelper.go +++ b/util/JsonHelper.go @@ -2,7 +2,7 @@ package util import "encoding/json" -// IsEmptyJSON checks if a given string represents an empty JSON object +// IsEmptyJSONForJsonString checks if a given string represents an empty JSON object func IsEmptyJSONForJsonString(jsonStr string) (bool, error) { var data interface{} err := json.Unmarshal([]byte(jsonStr), &data) @@ -19,3 +19,7 @@ func IsEmptyJSONForJsonString(jsonStr string) (bool, error) { // If not a JSON object, return false return false, nil } + +func GetEmptyJSON() []byte { + return []byte("{}") +} diff --git a/util/context-utils.go b/util/context-utils.go index 041110349b..6888f9e115 100644 --- a/util/context-utils.go +++ b/util/context-utils.go @@ -37,3 +37,10 @@ func GetIsSuperAdminFromContext(ctx context.Context) (bool, error) { } return false, fmt.Errorf("context not valid, isSuperAdmin flag not set correctly %v", flag) } + +// SetTokenInContext - Set token in context +// NOTE: In OSS we don't have the token embedded in ctx already. +// TODO: Support NewRequestCtx in OSS as well. +func SetTokenInContext(ctx context.Context, token string) context.Context { + return context.WithValue(ctx, "token", token) +} diff --git a/wire_gen.go b/wire_gen.go index ac459536ce..fceb61da7d 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -1,6 +1,6 @@ // Code generated by Wire. DO NOT EDIT. -//go:generate go run -mod=mod github.com/google/wire/cmd/wire +//go:generate go run github.com/google/wire/cmd/wire //go:build !wireinject // +build !wireinject @@ -189,6 +189,7 @@ import ( "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef" read12 "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef/read" read7 "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/read" + "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/validator" "github.com/devtron-labs/devtron/pkg/deployment/manifest/publish" "github.com/devtron-labs/devtron/pkg/deployment/providerConfig" "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps" @@ -593,7 +594,8 @@ func InitializeApp() (*App, error) { appStatusServiceImpl := appStatus2.NewAppStatusServiceImpl(appStatusRepositoryImpl, sugaredLogger, enforcerImpl, enforcerUtilImpl) installedAppReadServiceImpl := read5.NewInstalledAppReadServiceImpl(installedAppReadServiceEAImpl) chartRefReadServiceImpl := read12.NewChartRefReadServiceImpl(sugaredLogger, chartRefRepositoryImpl) - chartRefServiceImpl := chartRef.NewChartRefServiceImpl(sugaredLogger, chartRefRepositoryImpl, chartRefReadServiceImpl, chartTemplateServiceImpl, chartRepositoryImpl, mergeUtil) + globalStrategyMetadataChartRefMappingRepositoryImpl := chartRepoRepository.NewGlobalStrategyMetadataChartRefMappingRepositoryImpl(db, sugaredLogger) + chartRefServiceImpl := chartRef.NewChartRefServiceImpl(sugaredLogger, chartRefRepositoryImpl, chartRefReadServiceImpl, chartTemplateServiceImpl, chartRepositoryImpl, mergeUtil, globalStrategyMetadataChartRefMappingRepositoryImpl) deploymentTemplateServiceImpl := deploymentTemplate.NewDeploymentTemplateServiceImpl(sugaredLogger, chartRefServiceImpl, chartTemplateServiceImpl, chartRepositoryImpl, deploymentConfigServiceImpl) appListingRepositoryQueryBuilder := helper.NewAppListingRepositoryQueryBuilder(sugaredLogger) appListingRepositoryImpl := repository2.NewAppListingRepositoryImpl(sugaredLogger, db, appListingRepositoryQueryBuilder, environmentRepositoryImpl) @@ -710,8 +712,7 @@ func InitializeApp() (*App, error) { cdPipelineConfigServiceImpl := pipeline.NewCdPipelineConfigServiceImpl(sugaredLogger, pipelineRepositoryImpl, environmentRepositoryImpl, pipelineConfigRepositoryImpl, appWorkflowRepositoryImpl, pipelineStageServiceImpl, appRepositoryImpl, appServiceImpl, deploymentGroupRepositoryImpl, ciCdPipelineOrchestratorImpl, appStatusRepositoryImpl, ciPipelineRepositoryImpl, prePostCdScriptHistoryServiceImpl, clusterRepositoryImpl, helmAppServiceImpl, enforcerUtilImpl, pipelineStrategyHistoryServiceImpl, chartRepositoryImpl, resourceGroupServiceImpl, propertiesConfigServiceImpl, deploymentTemplateHistoryServiceImpl, scopedVariableManagerImpl, environmentVariables, customTagServiceImpl, ciPipelineConfigServiceImpl, buildPipelineSwitchServiceImpl, argoClientWrapperServiceImpl, deployedAppMetricsServiceImpl, gitOpsConfigReadServiceImpl, gitOpsValidationServiceImpl, gitOperationServiceImpl, chartServiceImpl, imageDigestPolicyServiceImpl, pipelineConfigEventPublishServiceImpl, deploymentTypeOverrideServiceImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl, chartRefReadServiceImpl, chartTemplateServiceImpl, gitFactory, clusterReadServiceImpl, installedAppReadServiceImpl, chartReadServiceImpl, helmAppReadServiceImpl) appArtifactManagerImpl := pipeline.NewAppArtifactManagerImpl(sugaredLogger, cdWorkflowRepositoryImpl, userServiceImpl, imageTaggingServiceImpl, ciArtifactRepositoryImpl, ciWorkflowRepositoryImpl, pipelineStageServiceImpl, cdPipelineConfigServiceImpl, dockerArtifactStoreRepositoryImpl, ciPipelineRepositoryImpl, ciTemplateReadServiceImpl) devtronAppCMCSServiceImpl := pipeline.NewDevtronAppCMCSServiceImpl(sugaredLogger, appServiceImpl, attributesRepositoryImpl) - globalStrategyMetadataChartRefMappingRepositoryImpl := chartRepoRepository.NewGlobalStrategyMetadataChartRefMappingRepositoryImpl(db, sugaredLogger) - devtronAppStrategyServiceImpl := pipeline.NewDevtronAppStrategyServiceImpl(sugaredLogger, chartRepositoryImpl, globalStrategyMetadataChartRefMappingRepositoryImpl, ciCdPipelineOrchestratorImpl, cdPipelineConfigServiceImpl) + devtronAppStrategyServiceImpl := pipeline.NewDevtronAppStrategyServiceImpl(sugaredLogger, chartRepositoryImpl, globalStrategyMetadataChartRefMappingRepositoryImpl, ciCdPipelineOrchestratorImpl, cdPipelineConfigServiceImpl, chartRefServiceImpl) cdWorkflowCommonServiceImpl, err := cd.NewCdWorkflowCommonServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl, pipelineStatusTimelineServiceImpl, pipelineRepositoryImpl, pipelineStatusTimelineRepositoryImpl, deploymentConfigServiceImpl, cdWorkflowRunnerServiceImpl) if err != nil { return nil, err @@ -728,14 +729,15 @@ func InitializeApp() (*App, error) { appDeploymentTypeChangeManagerImpl := pipeline.NewAppDeploymentTypeChangeManagerImpl(sugaredLogger, pipelineRepositoryImpl, appServiceImpl, appStatusRepositoryImpl, helmAppServiceImpl, appArtifactManagerImpl, cdPipelineConfigServiceImpl, gitOpsConfigReadServiceImpl, chartServiceImpl, workflowEventPublishServiceImpl, deploymentConfigServiceImpl, chartReadServiceImpl, deploymentConfigReadServiceImpl) devtronAppConfigServiceImpl := pipeline.NewDevtronAppConfigServiceImpl(sugaredLogger, ciCdPipelineOrchestratorImpl, appRepositoryImpl, pipelineRepositoryImpl, resourceGroupServiceImpl, enforcerUtilImpl, ciMaterialConfigServiceImpl) pipelineBuilderImpl := pipeline.NewPipelineBuilderImpl(sugaredLogger, gitMaterialReadServiceImpl, chartRepositoryImpl, ciPipelineConfigServiceImpl, ciMaterialConfigServiceImpl, appArtifactManagerImpl, devtronAppCMCSServiceImpl, devtronAppStrategyServiceImpl, appDeploymentTypeChangeManagerImpl, cdPipelineConfigServiceImpl, devtronAppConfigServiceImpl) - deploymentTemplateValidationServiceImpl := deploymentTemplate.NewDeploymentTemplateValidationServiceImpl(sugaredLogger, chartRefServiceImpl, scopedVariableManagerImpl) + deploymentTemplateValidationServiceEntImpl := validator.NewDeploymentTemplateValidationServiceEntImpl() + deploymentTemplateValidationServiceImpl := validator.NewDeploymentTemplateValidationServiceImpl(sugaredLogger, chartRefServiceImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, deploymentTemplateValidationServiceEntImpl) devtronAppGitOpConfigServiceImpl := gitOpsConfig.NewDevtronAppGitOpConfigServiceImpl(sugaredLogger, chartRepositoryImpl, chartServiceImpl, gitOpsConfigReadServiceImpl, gitOpsValidationServiceImpl, argoClientWrapperServiceImpl, deploymentConfigServiceImpl, chartReadServiceImpl) cdHandlerImpl := pipeline.NewCdHandlerImpl(sugaredLogger, userServiceImpl, cdWorkflowRepositoryImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, ciPipelineMaterialRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, ciWorkflowRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, imageTaggingServiceImpl, k8sServiceImpl, workflowServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl, customTagServiceImpl, deploymentConfigServiceImpl, workFlowStageStatusServiceImpl, cdWorkflowRunnerServiceImpl) appWorkflowServiceImpl := appWorkflow2.NewAppWorkflowServiceImpl(sugaredLogger, appWorkflowRepositoryImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, appRepositoryImpl, userAuthServiceImpl, chartServiceImpl, deploymentConfigServiceImpl, pipelineBuilderImpl) appCloneServiceImpl := appClone.NewAppCloneServiceImpl(sugaredLogger, pipelineBuilderImpl, attributesServiceImpl, chartServiceImpl, configMapServiceImpl, appWorkflowServiceImpl, appListingServiceImpl, propertiesConfigServiceImpl, pipelineStageServiceImpl, ciTemplateReadServiceImpl, appRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, ciPipelineConfigServiceImpl, gitOpsConfigReadServiceImpl, chartReadServiceImpl) deploymentTemplateRepositoryImpl := repository2.NewDeploymentTemplateRepositoryImpl(db, sugaredLogger) deploymentTemplateHistoryReadServiceImpl := read7.NewDeploymentTemplateHistoryReadServiceImpl(sugaredLogger, deploymentTemplateHistoryRepositoryImpl, scopedVariableManagerImpl) - generateManifestDeploymentTemplateServiceImpl, err := generateManifest.NewDeploymentTemplateServiceImpl(sugaredLogger, chartServiceImpl, appListingServiceImpl, deploymentTemplateRepositoryImpl, helmAppReadServiceImpl, chartTemplateServiceImpl, helmAppClientImpl, k8sServiceImpl, propertiesConfigServiceImpl, environmentRepositoryImpl, appRepositoryImpl, scopedVariableManagerImpl, chartRefServiceImpl, pipelineOverrideRepositoryImpl, chartRepositoryImpl, pipelineRepositoryImpl, utilMergeUtil, deploymentTemplateHistoryReadServiceImpl, deploymentConfigReadServiceImpl) + generateManifestDeploymentTemplateServiceImpl, err := generateManifest.NewDeploymentTemplateServiceImpl(sugaredLogger, chartServiceImpl, chartReadServiceImpl, appListingServiceImpl, deploymentTemplateRepositoryImpl, helmAppReadServiceImpl, chartTemplateServiceImpl, helmAppClientImpl, k8sServiceImpl, propertiesConfigServiceImpl, environmentRepositoryImpl, appRepositoryImpl, scopedVariableManagerImpl, chartRefServiceImpl, pipelineOverrideRepositoryImpl, chartRepositoryImpl, pipelineRepositoryImpl, utilMergeUtil, deploymentTemplateHistoryReadServiceImpl, deploymentConfigReadServiceImpl) if err != nil { return nil, err }