diff --git a/Dockerfile b/Dockerfile index 1d80a3f0a7..9db2ef5900 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,52 +1,46 @@ FROM golang:1.21 AS build-env -RUN echo $GOPATH -RUN apt update -RUN apt install git gcc musl-dev make -y -RUN go install github.com/google/wire/cmd/wire@latest +RUN echo $GOPATH && \ + apt update && \ + apt install git gcc musl-dev make -y && \ + go install github.com/google/wire/cmd/wire@latest + WORKDIR /go/src/github.com/devtron-labs/devtron + ADD . /go/src/github.com/devtron-labs/devtron/ + ADD ./vendor/github.com/Microsoft/ /go/src/github.com/devtron-labs/devtron/vendor/github.com/microsoft/ -RUN GOOS=linux make build-all + +RUN GOOS=linux make build # uncomment this post build arg FROM ubuntu:22.04@sha256:1b8d8ff4777f36f19bfe73ee4df61e3a0b789caeff29caa019539ec7c9a57f95 as devtron-all -RUN apt update -RUN apt install ca-certificates git curl -y -RUN apt clean autoclean -RUN apt autoremove -y && rm -rf /var/lib/apt/lists/* -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/devtron . -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/auth_model.conf . -#COPY --from=build-env /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets/ /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/argocd-assets/ /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/devtron-reference-helm-charts scripts/devtron-reference-helm-charts -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/sql scripts/sql -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/casbin scripts/casbin -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/argo-assets/APPLICATION_TEMPLATE.tmpl scripts/argo-assets/APPLICATION_TEMPLATE.tmpl - -COPY ./git-ask-pass.sh /git-ask-pass.sh -RUN chmod +x /git-ask-pass.sh - -RUN useradd -ms /bin/bash devtron -RUN chown -R devtron:devtron ./devtron -RUN chown -R devtron:devtron ./git-ask-pass.sh -RUN chown -R devtron:devtron ./auth_model.conf -RUN chown -R devtron:devtron ./scripts +RUN apt update && \ + apt install ca-certificates git curl -y && \ + apt clean autoclean && \ + apt autoremove -y && \ + rm -rf /var/lib/apt/lists/* && \ + useradd -ms /bin/bash devtron -USER devtron +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/devtron . + +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/auth_model.conf . -CMD ["./devtron"] +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/argocd-assets/ /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/devtron-reference-helm-charts scripts/devtron-reference-helm-charts -#FROM alpine:3.15.0 as devtron-ea +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/sql scripts/sql -#RUN apk add --no-cache ca-certificates -#COPY --from=build-env /go/src/github.com/devtron-labs/devtron/auth_model.conf . -#COPY --from=build-env /go/src/github.com/devtron-labs/devtron/cmd/external-app/devtron-ea . +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/casbin scripts/casbin -#COPY --from=build-env /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets/ /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets -#COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/devtron-reference-helm-charts scripts/devtron-reference-helm-charts -#COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/argo-assets/APPLICATION_TEMPLATE.JSON scripts/argo-assets/APPLICATION_TEMPLATE.JSON +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/argo-assets/APPLICATION_TEMPLATE.tmpl scripts/argo-assets/APPLICATION_TEMPLATE.tmpl + +COPY --chown=devtron:devtron ./git-ask-pass.sh /git-ask-pass.sh + +RUN chmod +x /git-ask-pass.sh + +USER devtron -#CMD ["./devtron-ea"] +CMD ["./devtron"] \ No newline at end of file diff --git a/DockerfileEA b/DockerfileEA index bd05f7e43f..d80cfd7cd1 100644 --- a/DockerfileEA +++ b/DockerfileEA @@ -1,33 +1,40 @@ FROM golang:1.21 AS build-env -RUN echo $GOPATH -RUN apt update -RUN apt install git gcc musl-dev make -y -RUN go install github.com/google/wire/cmd/wire@latest +RUN echo $GOPATH && \ + apt update && \ + apt install git gcc musl-dev make -y && \ + go install github.com/google/wire/cmd/wire@latest + WORKDIR /go/src/github.com/devtron-labs/devtron + ADD . /go/src/github.com/devtron-labs/devtron/ + ADD ./vendor/github.com/Microsoft/ /go/src/github.com/devtron-labs/devtron/vendor/github.com/microsoft/ + RUN GOOS=linux make build-all FROM ubuntu:22.04@sha256:1b8d8ff4777f36f19bfe73ee4df61e3a0b789caeff29caa019539ec7c9a57f95 as devtron-ea -RUN apt update -RUN apt install ca-certificates curl -y -RUN apt clean autoclean -RUN apt autoremove -y && rm -rf /var/lib/apt/lists/* -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/auth_model.conf . -COPY --from=build-env /go/src/github.com/devtron-labs/devtron/cmd/external-app/devtron-ea . +RUN apt update && \ + apt install ca-certificates curl -y && \ + apt clean autoclean && \ + apt autoremove -y && rm -rf /var/lib/apt/lists/* && \ + useradd -ms /bin/bash devtron + +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/auth_model.conf . + +COPY --chown=devtron:devtron --from=build-env /go/src/github.com/devtron-labs/devtron/cmd/external-app/devtron-ea . -#COPY --from=build-env /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets/ /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets COPY --from=build-env /go/src/github.com/devtron-labs/devtron/argocd-assets/ /go/src/github.com/devtron-labs/devtron/vendor/github.com/argoproj/argo-cd/assets + COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/devtron-reference-helm-charts scripts/devtron-reference-helm-charts + COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/sql scripts/sql + COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/casbin scripts/casbin + COPY --from=build-env /go/src/github.com/devtron-labs/devtron/scripts/argo-assets/APPLICATION_TEMPLATE.tmpl scripts/argo-assets/APPLICATION_TEMPLATE.tmpl -RUN useradd -ms /bin/bash devtron -RUN chown -R devtron:devtron ./devtron-ea -RUN chown -R devtron:devtron ./auth_model.conf RUN chown -R devtron:devtron ./scripts USER devtron diff --git a/Wire.go b/Wire.go index eb0edb3b85..8d6b8d5a98 100644 --- a/Wire.go +++ b/Wire.go @@ -43,7 +43,6 @@ import ( "github.com/devtron-labs/devtron/api/externalLink" fluxApplication "github.com/devtron-labs/devtron/api/fluxApplication" client "github.com/devtron-labs/devtron/api/helm-app" - "github.com/devtron-labs/devtron/api/infraConfig" "github.com/devtron-labs/devtron/api/k8s" "github.com/devtron-labs/devtron/api/module" "github.com/devtron-labs/devtron/api/resourceScan" @@ -79,8 +78,10 @@ import ( "github.com/devtron-labs/devtron/cel" "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/client/argocdServer/application" + "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/client/argocdServer/certificate" cluster2 "github.com/devtron-labs/devtron/client/argocdServer/cluster" + acdConfig "github.com/devtron-labs/devtron/client/argocdServer/config" "github.com/devtron-labs/devtron/client/argocdServer/connection" "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient" repocreds "github.com/devtron-labs/devtron/client/argocdServer/repocreds" @@ -129,7 +130,8 @@ import ( "github.com/devtron-labs/devtron/pkg/chart/gitOpsConfig" chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" "github.com/devtron-labs/devtron/pkg/commonService" - "github.com/devtron-labs/devtron/pkg/configDiff" + "github.com/devtron-labs/devtron/pkg/config" + "github.com/devtron-labs/devtron/pkg/config/configDiff" delete2 "github.com/devtron-labs/devtron/pkg/delete" deployment2 "github.com/devtron-labs/devtron/pkg/deployment" "github.com/devtron-labs/devtron/pkg/deployment/common" @@ -143,9 +145,7 @@ import ( "github.com/devtron-labs/devtron/pkg/generateManifest" "github.com/devtron-labs/devtron/pkg/gitops" "github.com/devtron-labs/devtron/pkg/imageDigestPolicy" - repository11 "github.com/devtron-labs/devtron/pkg/infraConfig/repository" - infraConfigService "github.com/devtron-labs/devtron/pkg/infraConfig/service" - "github.com/devtron-labs/devtron/pkg/infraConfig/units" + "github.com/devtron-labs/devtron/pkg/infraConfig" "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs" repository7 "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs/repository" "github.com/devtron-labs/devtron/pkg/notifier" @@ -153,7 +153,6 @@ import ( "github.com/devtron-labs/devtron/pkg/pipeline/executors" history3 "github.com/devtron-labs/devtron/pkg/pipeline/history" repository3 "github.com/devtron-labs/devtron/pkg/pipeline/history/repository" - "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders" repository5 "github.com/devtron-labs/devtron/pkg/pipeline/repository" "github.com/devtron-labs/devtron/pkg/pipeline/types" "github.com/devtron-labs/devtron/pkg/plugin" @@ -229,7 +228,7 @@ func InitializeApp() (*App, error) { connection.SettingsManager, // auth.GetConfigForDevtronApps, - connection.GetConfig, + bean.GetConfig, wire.Bind(new(session2.ServiceClient), new(*middleware.LoginService)), sse.NewSSE, @@ -278,20 +277,6 @@ func InitializeApp() (*App, error) { wire.Bind(new(dashboardEvent.DashboardTelemetryRouter), new(*dashboardEvent.DashboardTelemetryRouterImpl)), - repository11.NewInfraProfileRepositoryImpl, - wire.Bind(new(repository11.InfraConfigRepository), new(*repository11.InfraConfigRepositoryImpl)), - - units.NewUnits, - infraConfigService.NewInfraConfigServiceImpl, - wire.Bind(new(infraConfigService.InfraConfigService), new(*infraConfigService.InfraConfigServiceImpl)), - infraProviders.NewInfraProviderImpl, - wire.Bind(new(infraProviders.InfraProvider), new(*infraProviders.InfraProviderImpl)), - infraConfig.NewInfraConfigRestHandlerImpl, - wire.Bind(new(infraConfig.InfraConfigRestHandler), new(*infraConfig.InfraConfigRestHandlerImpl)), - - infraConfig.NewInfraProfileRouterImpl, - wire.Bind(new(infraConfig.InfraConfigRouter), new(*infraConfig.InfraConfigRouterImpl)), - router.NewMuxRouter, app2.NewAppRepositoryImpl, @@ -526,6 +511,10 @@ func InitializeApp() (*App, error) { chartConfig.NewConfigMapRepositoryImpl, wire.Bind(new(chartConfig.ConfigMapRepository), new(*chartConfig.ConfigMapRepositoryImpl)), + config.WireSet, + + infraConfig.WireSet, + notifier.NewSESNotificationServiceImpl, wire.Bind(new(notifier.SESNotificationService), new(*notifier.SESNotificationServiceImpl)), @@ -926,6 +915,7 @@ func InitializeApp() (*App, error) { wire.Bind(new(resourceQualifiers.QualifierMappingService), new(*resourceQualifiers.QualifierMappingServiceImpl)), argocdServer.NewArgoClientWrapperServiceImpl, + argocdServer.NewArgoClientWrapperServiceEAImpl, wire.Bind(new(argocdServer.ArgoClientWrapperService), new(*argocdServer.ArgoClientWrapperServiceImpl)), pipeline.NewPluginInputVariableParserImpl, @@ -937,7 +927,7 @@ func InitializeApp() (*App, error) { wire.Bind(new(imageDigestPolicy.ImageDigestPolicyService), new(*imageDigestPolicy.ImageDigestPolicyServiceImpl)), certificate.NewServiceClientImpl, - wire.Bind(new(certificate.Client), new(*certificate.ServiceClientImpl)), + wire.Bind(new(certificate.ServiceClient), new(*certificate.ServiceClientImpl)), appStoreRestHandler.FullModeWireSet, @@ -950,14 +940,17 @@ func InitializeApp() (*App, error) { common.NewDeploymentConfigServiceImpl, wire.Bind(new(common.DeploymentConfigService), new(*common.DeploymentConfigServiceImpl)), - repoCredsK8sClient.NewRepositorySecret, - wire.Bind(new(repoCredsK8sClient.RepositoryCreds), new(*repoCredsK8sClient.RepositorySecretImpl)), + repoCredsK8sClient.NewRepositoryCredsK8sClientImpl, + wire.Bind(new(repoCredsK8sClient.RepositoryCredsK8sClient), new(*repoCredsK8sClient.RepositoryCredsK8sClientImpl)), repocreds.NewServiceClientImpl, wire.Bind(new(repocreds.ServiceClient), new(*repocreds.ServiceClientImpl)), dbMigration.NewDbMigrationServiceImpl, wire.Bind(new(dbMigration.DbMigration), new(*dbMigration.DbMigrationServiceImpl)), + + acdConfig.NewArgoCDConfigGetter, + wire.Bind(new(acdConfig.ArgoCDConfigGetter), new(*acdConfig.ArgoCDConfigGetterImpl)), ) return &App{}, nil } diff --git a/api/appStore/InstalledAppRestHandler.go b/api/appStore/InstalledAppRestHandler.go index e2595d0562..3c39da689e 100644 --- a/api/appStore/InstalledAppRestHandler.go +++ b/api/appStore/InstalledAppRestHandler.go @@ -37,7 +37,6 @@ import ( "time" "github.com/devtron-labs/devtron/api/restHandler/common" - "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/client/cron" "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/middleware" @@ -84,7 +83,6 @@ type InstalledAppRestHandlerImpl struct { chartGroupService chartGroup.ChartGroupService validator *validator.Validate clusterService cluster.ClusterService - acdServiceClient application.ServiceClient appStoreDeploymentService service.AppStoreDeploymentService appStoreDeploymentDBService service.AppStoreDeploymentDBService helmAppClient client.HelmAppClient @@ -100,7 +98,7 @@ func NewInstalledAppRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService u installedAppService FullMode.InstalledAppDBExtendedService, installedAppResourceService resource.InstalledAppResourceService, chartGroupService chartGroup.ChartGroupService, validator *validator.Validate, clusterService cluster.ClusterService, - acdServiceClient application.ServiceClient, appStoreDeploymentService service.AppStoreDeploymentService, + appStoreDeploymentService service.AppStoreDeploymentService, appStoreDeploymentDBService service.AppStoreDeploymentDBService, helmAppClient client.HelmAppClient, @@ -120,7 +118,6 @@ func NewInstalledAppRestHandlerImpl(Logger *zap.SugaredLogger, userAuthService u chartGroupService: chartGroupService, validator: validator, clusterService: clusterService, - acdServiceClient: acdServiceClient, appStoreDeploymentService: appStoreDeploymentService, appStoreDeploymentDBService: appStoreDeploymentDBService, helmAppClient: helmAppClient, diff --git a/api/infraConfig/restHandler.go b/api/infraConfig/restHandler.go index bbcb3c48eb..6d7b550fc2 100644 --- a/api/infraConfig/restHandler.go +++ b/api/infraConfig/restHandler.go @@ -18,14 +18,18 @@ package infraConfig import ( "encoding/json" + "fmt" "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin" "github.com/devtron-labs/devtron/pkg/auth/user" "github.com/devtron-labs/devtron/pkg/infraConfig/adapter" - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v0" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + errors2 "github.com/devtron-labs/devtron/pkg/infraConfig/errors" "github.com/devtron-labs/devtron/pkg/infraConfig/service" - util2 "github.com/devtron-labs/devtron/pkg/infraConfig/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/util" "github.com/devtron-labs/devtron/util/rbac" + "github.com/go-pg/pg" "github.com/gorilla/mux" "github.com/pkg/errors" "go.uber.org/zap" @@ -42,13 +46,15 @@ type InfraConfigRestHandler interface { GetProfileV0(w http.ResponseWriter, r *http.Request) // Deprecated: UpdateInfraProfileV0 is deprecated in favour of UpdateInfraProfile UpdateInfraProfileV0(w http.ResponseWriter, r *http.Request) + + InfraConfigRestHandlerEnt } + type InfraConfigRestHandlerImpl struct { logger *zap.SugaredLogger infraProfileService service.InfraConfigService userService user.UserService enforcer casbin.Enforcer - enforcerUtil rbac.EnforcerUtil validator *validator.Validate } @@ -58,7 +64,6 @@ func NewInfraConfigRestHandlerImpl(logger *zap.SugaredLogger, infraProfileServic infraProfileService: infraProfileService, userService: userService, enforcer: enforcer, - enforcerUtil: enforcerUtil, validator: validator, } } @@ -76,29 +81,48 @@ func (handler *InfraConfigRestHandlerImpl) GetProfile(w http.ResponseWriter, r * } identifier := r.URL.Query().Get("name") - if len(identifier) == 0 { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) + common.WriteJsonResp(w, errors.New(errors2.InvalidProfileName), nil, http.StatusBadRequest) return } profileName := strings.ToLower(identifier) - var profile *bean.ProfileBeanDto - if profileName != bean.GLOBAL_PROFILE_NAME { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) - return + var profile *v1.ProfileBeanDto + if profileName != v1.GLOBAL_PROFILE_NAME { + profile, err = handler.infraProfileService.GetProfileByName(profileName) + if err != nil { + statusCode := http.StatusInternalServerError + if errors.Is(err, pg.ErrNoRows) { + err = errors.New(fmt.Sprintf("profile %s not found", profileName)) + statusCode = http.StatusNotFound + } + common.WriteJsonResp(w, err, nil, statusCode) + return + } } - defaultProfile, err := handler.infraProfileService.GetProfileByName(profileName) + + defaultProfile, err := handler.infraProfileService.GetProfileByName(v1.GLOBAL_PROFILE_NAME) if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + statusCode := http.StatusInternalServerError + if errors.Is(err, pg.ErrNoRows) { + err = errors.New(fmt.Sprintf("profile %s not found", v1.GLOBAL_PROFILE_NAME)) + statusCode = http.StatusNotFound + } + common.WriteJsonResp(w, err, nil, statusCode) return } - profile = defaultProfile - - resp := bean.ProfileResponse{ + if profileName == v1.GLOBAL_PROFILE_NAME { + profile = defaultProfile + } + resp := v1.ProfileResponse{ Profile: *profile, } - resp.ConfigurationUnits = handler.infraProfileService.GetConfigurationUnits() - resp.DefaultConfigurations = defaultProfile.Configurations + resp.ConfigurationUnits, err = handler.infraProfileService.GetConfigurationUnits() + if err != nil { + handler.logger.Errorw("error in getting configuration units", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + resp.DefaultConfigurations = defaultProfile.GetConfigurations() common.WriteJsonResp(w, nil, resp, http.StatusOK) } @@ -117,12 +141,15 @@ func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfile(w http.ResponseWri //vars := mux.Vars(r) val := r.URL.Query().Get("name") if len(val) == 0 { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) + common.WriteJsonResp(w, errors.New("name is required"), nil, http.StatusBadRequest) return } profileName := strings.ToLower(val) - - payload := &bean.ProfileBeanDto{} + if profileName == "" { + common.WriteJsonResp(w, errors.New(errors2.InvalidProfileName), nil, http.StatusBadRequest) + return + } + payload := &v1.ProfileBeanDto{} decoder := json.NewDecoder(r.Body) err = decoder.Decode(payload) if err != nil { @@ -130,15 +157,10 @@ func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfile(w http.ResponseWri common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - //handler.validator.RegisterValidation("validateValue", ValidateValue) - payload.Name = strings.ToLower(payload.Name) err = handler.validator.Struct(payload) if err != nil { - err = errors.Wrap(err, bean.PayloadValidationError) + err = errors.Wrap(err, errors2.PayloadValidationError) common.WriteJsonResp(w, err, nil, http.StatusBadRequest) - } - if !util2.IsValidProfileNameRequested(profileName, payload.Name) { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) return } err = handler.infraProfileService.UpdateProfile(userId, profileName, payload) @@ -150,7 +172,7 @@ func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfile(w http.ResponseWri common.WriteJsonResp(w, nil, nil, http.StatusOK) } -// Deprecated +// Deprecated: GetProfileV0 is deprecated in favour of GetProfile func (handler *InfraConfigRestHandlerImpl) GetProfileV0(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { @@ -166,34 +188,53 @@ func (handler *InfraConfigRestHandlerImpl) GetProfileV0(w http.ResponseWriter, r vars := mux.Vars(r) profileName := strings.ToLower(vars["name"]) if profileName == "" { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) + common.WriteJsonResp(w, errors.New(errors2.InvalidProfileName), nil, http.StatusBadRequest) return } - if profileName != bean.DEFAULT_PROFILE_NAME { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) - return + var profileV0 *v0.ProfileBeanV0 + if profileName != v1.DEFAULT_PROFILE_NAME { + profileV1, err := handler.infraProfileService.GetProfileByName(profileName) + profileV0 = adapter.GetV0ProfileBean(profileV1) + if err != nil { + statusCode := http.StatusInternalServerError + if errors.Is(err, pg.ErrNoRows) { + err = errors.New(fmt.Sprintf("profile %s not found", profileName)) + statusCode = http.StatusNotFound + } + common.WriteJsonResp(w, err, nil, statusCode) + return + } } - profileName = bean.GLOBAL_PROFILE_NAME - - var profile *bean.ProfileBeanV0 - defaultProfileV1, err := handler.infraProfileService.GetProfileByName(profileName) - defaultProfileV0 := adapter.GetV0ProfileBean(defaultProfileV1) + defaultProfileV1, err := handler.infraProfileService.GetProfileByName(v1.GLOBAL_PROFILE_NAME) if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + statusCode := http.StatusInternalServerError + if errors.Is(err, pg.ErrNoRows) { + err = errors.New(fmt.Sprintf("profile %s not found", v1.GLOBAL_PROFILE_NAME)) + statusCode = http.StatusNotFound + } + common.WriteJsonResp(w, err, nil, statusCode) return } - profile = defaultProfileV0 - resp := bean.ProfileResponseV0{ - Profile: *profile, + defaultProfileV0 := adapter.GetV0ProfileBean(defaultProfileV1) + if profileName == v1.DEFAULT_PROFILE_NAME { + profileV0 = defaultProfileV0 + } + resp := v0.ProfileResponseV0{ + Profile: *profileV0, } - resp.ConfigurationUnits = handler.infraProfileService.GetConfigurationUnits() + resp.ConfigurationUnits, err = handler.infraProfileService.GetConfigurationUnits() + if err != nil { + handler.logger.Errorw("error in getting configuration units", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + //returning the default configuration for UI inheriting purpose resp.DefaultConfigurations = defaultProfileV0.Configurations common.WriteJsonResp(w, nil, resp, http.StatusOK) } -// Deprecated func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfileV0(w http.ResponseWriter, r *http.Request) { userId, err := handler.userService.GetLoggedInUser(r) if userId == 0 || err != nil { @@ -209,10 +250,10 @@ func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfileV0(w http.ResponseW vars := mux.Vars(r) profileName := strings.ToLower(vars["name"]) if profileName == "" { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) + common.WriteJsonResp(w, errors.New(errors2.InvalidProfileName), nil, http.StatusBadRequest) return } - payload := &bean.ProfileBeanV0{} + payload := &v0.ProfileBeanV0{} decoder := json.NewDecoder(r.Body) err = decoder.Decode(payload) if err != nil { @@ -220,27 +261,25 @@ func (handler *InfraConfigRestHandlerImpl) UpdateInfraProfileV0(w http.ResponseW common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - payload.Name = strings.ToLower(payload.Name) err = handler.validator.Struct(payload) if err != nil { - err = errors.Wrap(err, bean.PayloadValidationError) + err = errors.Wrap(err, errors2.PayloadValidationError) common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return } - if !util2.IsValidProfileNameRequestedV0(profileName, payload.Name) { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) + if !util.IsValidProfileNameRequestedV0(profileName, payload.GetName()) { + common.WriteJsonResp(w, errors.New(errors2.InvalidProfileName), nil, http.StatusBadRequest) return } - if payload.Name != bean.DEFAULT_PROFILE_NAME { - common.WriteJsonResp(w, errors.New(bean.InvalidProfileName), nil, http.StatusBadRequest) + if profileName == v1.DEFAULT_PROFILE_NAME && payload.GetName() != v1.DEFAULT_PROFILE_NAME { + common.WriteJsonResp(w, errors.New(errors2.InvalidProfileName), nil, http.StatusBadRequest) return } - - profileName = bean.GLOBAL_PROFILE_NAME - payloadV1 := adapter.GetV1ProfileBean(payload) - err = handler.infraProfileService.UpdateProfile(userId, profileName, payloadV1) + payloadV1 := adapter.ConvertToV1ProfileBean(payload) + err = handler.infraProfileService.UpdateProfileV0(userId, profileName, payloadV1) if err != nil { handler.logger.Errorw("error in updating profile and configurations", "profileName", profileName, "payLoad", payload, "err", err) - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } common.WriteJsonResp(w, nil, nil, http.StatusOK) diff --git a/api/infraConfig/restHandler_ent.go b/api/infraConfig/restHandler_ent.go new file mode 100644 index 0000000000..56e8318684 --- /dev/null +++ b/api/infraConfig/restHandler_ent.go @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package infraConfig + +type InfraConfigRestHandlerEnt interface { +} diff --git a/api/resourceScan/wire_scan.go b/api/resourceScan/wire_scan.go index 1ea4db1e93..0d4d6b9db5 100644 --- a/api/resourceScan/wire_scan.go +++ b/api/resourceScan/wire_scan.go @@ -1,5 +1,17 @@ /* * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package resourceScan diff --git a/api/restHandler/BulkUpdateRestHandler.go b/api/restHandler/BulkUpdateRestHandler.go index 2db6a9497e..464bd55fbe 100644 --- a/api/restHandler/BulkUpdateRestHandler.go +++ b/api/restHandler/BulkUpdateRestHandler.go @@ -27,7 +27,6 @@ import ( "strings" "github.com/devtron-labs/devtron/api/restHandler/common" - "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/client/gitSensor" "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" @@ -65,7 +64,6 @@ type BulkUpdateRestHandlerImpl struct { bulkUpdateService bulkAction.BulkUpdateService chartService chart.ChartService propertiesConfigService pipeline.PropertiesConfigService - application application.ServiceClient userAuthService user.UserService validator *validator.Validate teamService team.TeamService @@ -86,7 +84,6 @@ func NewBulkUpdateRestHandlerImpl(pipelineBuilder pipeline.PipelineBuilder, logg bulkUpdateService bulkAction.BulkUpdateService, chartService chart.ChartService, propertiesConfigService pipeline.PropertiesConfigService, - application application.ServiceClient, userAuthService user.UserService, teamService team.TeamService, enforcer casbin.Enforcer, @@ -107,7 +104,6 @@ func NewBulkUpdateRestHandlerImpl(pipelineBuilder pipeline.PipelineBuilder, logg bulkUpdateService: bulkUpdateService, chartService: chartService, propertiesConfigService: propertiesConfigService, - application: application, userAuthService: userAuthService, validator: validator, teamService: teamService, diff --git a/api/restHandler/app/configDiff/DeploymentConfigurationRestHandler.go b/api/restHandler/app/configDiff/DeploymentConfigurationRestHandler.go index 3d6577c513..df88a3ea20 100644 --- a/api/restHandler/app/configDiff/DeploymentConfigurationRestHandler.go +++ b/api/restHandler/app/configDiff/DeploymentConfigurationRestHandler.go @@ -7,8 +7,8 @@ import ( "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin" "github.com/devtron-labs/devtron/pkg/auth/user" - "github.com/devtron-labs/devtron/pkg/configDiff" - "github.com/devtron-labs/devtron/pkg/configDiff/bean" + "github.com/devtron-labs/devtron/pkg/config/configDiff" + "github.com/devtron-labs/devtron/pkg/config/configDiff/bean" util2 "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/util/rbac" "github.com/gorilla/mux" diff --git a/api/restHandler/app/configDiff/utils.go b/api/restHandler/app/configDiff/utils.go index 49e0c59157..177214a8ac 100644 --- a/api/restHandler/app/configDiff/utils.go +++ b/api/restHandler/app/configDiff/utils.go @@ -2,7 +2,7 @@ package configDiff import ( "errors" - "github.com/devtron-labs/devtron/pkg/configDiff/bean" + "github.com/devtron-labs/devtron/pkg/config/configDiff/bean" ) var validConfigCategories = map[string]bool{bean.Secret.ToString(): true, bean.ConfigMap.ToString(): true, bean.DeploymentTemplate.ToString(): true, bean.PipelineStrategy.ToString(): true} diff --git a/client/argocdServer/ArgoClientWrapperService.go b/client/argocdServer/ArgoClientWrapperService.go index 8e78a0c1cf..54c7003ad7 100644 --- a/client/argocdServer/ArgoClientWrapperService.go +++ b/client/argocdServer/ArgoClientWrapperService.go @@ -21,6 +21,9 @@ import ( "encoding/json" "fmt" application2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" + "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate" + cluster2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster" + "github.com/argoproj/argo-cd/v2/pkg/apiclient/repocreds" repository2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/caarlos0/env" @@ -28,6 +31,11 @@ import ( "github.com/devtron-labs/devtron/client/argocdServer/adapter" "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/client/argocdServer/bean" + certificate2 "github.com/devtron-labs/devtron/client/argocdServer/certificate" + "github.com/devtron-labs/devtron/client/argocdServer/cluster" + config2 "github.com/devtron-labs/devtron/client/argocdServer/config" + bean2 "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient/bean" + repocreds2 "github.com/devtron-labs/devtron/client/argocdServer/repocreds" "github.com/devtron-labs/devtron/client/argocdServer/repository" "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/util" @@ -36,7 +44,7 @@ import ( "github.com/devtron-labs/devtron/util/retryFunc" "go.opentelemetry.io/otel" "go.uber.org/zap" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "google.golang.org/grpc" "strconv" "strings" "time" @@ -69,10 +77,14 @@ const ( ErrorOperationAlreadyInProgress = "another operation is already in progress" // this string is returned from argocd ) -type ArgoClientWrapperService interface { +type ApplicationClientWrapper interface { + ResourceTree(ctxt context.Context, query *application2.ResourcesQuery) (*v1alpha1.ApplicationTree, error) + GetArgoClient(ctxt context.Context) (application2.ApplicationServiceClient, *grpc.ClientConn, error) + GetApplicationResource(ctx context.Context, query *application2.ApplicationResourceRequest) (*application2.ApplicationResourceResponse, error) + DeleteArgoApp(ctx context.Context, appName string, cascadeDelete bool) (*application2.ApplicationResponse, error) - // GetArgoAppWithNormalRefresh - refresh app at argocd side - GetArgoAppWithNormalRefresh(context context.Context, argoAppName string) error + // GetArgoAppByName fetches an argoCd app by its name + GetArgoAppByName(ctx context.Context, appName string) (*v1alpha1.Application, error) // SyncArgoCDApplicationIfNeededAndRefresh - if ARGO_AUTO_SYNC_ENABLED=true, app will be refreshed to initiate refresh at argoCD side or else it will be synced and refreshed SyncArgoCDApplicationIfNeededAndRefresh(context context.Context, argoAppName string) error @@ -83,9 +95,6 @@ type ArgoClientWrapperService interface { // RegisterGitOpsRepoInArgoWithRetry - register a repository in argo-cd with retry mechanism RegisterGitOpsRepoInArgoWithRetry(ctx context.Context, gitOpsRepoUrl string, userId int32) error - // GetArgoAppByName fetches an argoCd app by its name - GetArgoAppByName(ctx context.Context, appName string) (*v1alpha1.Application, error) - // PatchArgoCdApp performs a patch operation on an argoCd app PatchArgoCdApp(ctx context.Context, dto *bean.ArgoCdAppPatchReqDto) error @@ -93,63 +102,156 @@ type ArgoClientWrapperService interface { IsArgoAppPatchRequired(argoAppSpec *v1alpha1.ApplicationSource, currentGitRepoUrl, currentChartPath string) bool // GetGitOpsRepoName returns the GitOps repository name, configured for the argoCd app - GetGitOpsRepoName(ctx context.Context, appName string) (gitOpsRepoName string, err error) + GetGitOpsRepoNameForApplication(ctx context.Context, appName string) (gitOpsRepoName string, err error) + + GetGitOpsRepoURLForApplication(ctx context.Context, appName string) (gitOpsRepoURL string, err error) +} + +type RepositoryClientWrapper interface { + RegisterGitOpsRepoInArgoWithRetry(ctx context.Context, gitOpsRepoUrl string, userId int32) error +} - GetGitOpsRepoURL(ctx context.Context, appName string) (gitOpsRepoURL string, err error) +type RepoCredsClientWrapper interface { + CreateRepoCreds(ctx context.Context, query *repocreds.RepoCredsCreateRequest) (*v1alpha1.RepoCreds, error) + AddOrUpdateOCIRegistry(username, password string, uniqueId int, registryUrl, repo string, isPublic bool) error + DeleteOCIRegistry(registryURL, repo string, ociRegistryId int) error + AddChartRepository(request bean2.ChartRepositoryAddRequest) error + UpdateChartRepository(request bean2.ChartRepositoryUpdateRequest) error + DeleteChartRepository(name, url string) error +} + +type CertificateClientWrapper interface { + CreateCertificate(ctx context.Context, query *certificate.RepositoryCertificateCreateRequest) (*v1alpha1.RepositoryCertificateList, error) + DeleteCertificate(ctx context.Context, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) +} + +type ClusterClientWrapper interface { + CreateCluster(ctx context.Context, clusterRequest *cluster2.ClusterCreateRequest) (*v1alpha1.Cluster, error) + UpdateCluster(ctx context.Context, clusterRequest *cluster2.ClusterUpdateRequest) (*v1alpha1.Cluster, error) +} + +type ArgoClientWrapperService interface { + ClusterClientWrapper + ApplicationClientWrapper + RepositoryClientWrapper + RepoCredsClientWrapper + CertificateClientWrapper } type ArgoClientWrapperServiceImpl struct { + acdApplicationClient application.ServiceClient + repositoryService repository.ServiceClient + clusterClient cluster.ServiceClient + repoCredsClient repocreds2.ServiceClient + CertificateClient certificate2.ServiceClient logger *zap.SugaredLogger - acdClient application.ServiceClient ACDConfig *ACDConfig - repositoryService repository.ServiceClient gitOpsConfigReadService config.GitOpsConfigReadService gitOperationService git.GitOperationService asyncRunnable *async.Runnable + acdConfigGetter config2.ArgoCDConfigGetter + *ArgoClientWrapperServiceEAImpl } -func NewArgoClientWrapperServiceImpl(logger *zap.SugaredLogger, acdClient application.ServiceClient, - ACDConfig *ACDConfig, repositoryService repository.ServiceClient, gitOpsConfigReadService config.GitOpsConfigReadService, - gitOperationService git.GitOperationService, asyncRunnable *async.Runnable) *ArgoClientWrapperServiceImpl { +func NewArgoClientWrapperServiceImpl( + acdClient application.ServiceClient, + repositoryService repository.ServiceClient, + clusterClient cluster.ServiceClient, + repocredsClient repocreds2.ServiceClient, + CertificateClient certificate2.ServiceClient, + logger *zap.SugaredLogger, + ACDConfig *ACDConfig, gitOpsConfigReadService config.GitOpsConfigReadService, + gitOperationService git.GitOperationService, asyncRunnable *async.Runnable, + acdConfigGetter config2.ArgoCDConfigGetter, + ArgoClientWrapperServiceEAImpl *ArgoClientWrapperServiceEAImpl, +) *ArgoClientWrapperServiceImpl { return &ArgoClientWrapperServiceImpl{ - logger: logger, - acdClient: acdClient, - ACDConfig: ACDConfig, - repositoryService: repositoryService, - gitOpsConfigReadService: gitOpsConfigReadService, - gitOperationService: gitOperationService, - asyncRunnable: asyncRunnable, + acdApplicationClient: acdClient, + repositoryService: repositoryService, + clusterClient: clusterClient, + repoCredsClient: repocredsClient, + CertificateClient: CertificateClient, + logger: logger, + ACDConfig: ACDConfig, + gitOpsConfigReadService: gitOpsConfigReadService, + gitOperationService: gitOperationService, + asyncRunnable: asyncRunnable, + acdConfigGetter: acdConfigGetter, + ArgoClientWrapperServiceEAImpl: ArgoClientWrapperServiceEAImpl, } } -func (impl *ArgoClientWrapperServiceImpl) GetArgoAppWithNormalRefresh(ctx context.Context, argoAppName string) error { - newCtx, span := otel.Tracer("orchestrator").Start(ctx, "ArgoClientWrapperServiceImpl.GetArgoAppWithNormalRefresh") - defer span.End() - refreshType := bean.RefreshTypeNormal - impl.logger.Debugw("trying to normal refresh application through get ", "argoAppName", argoAppName) - _, err := impl.acdClient.Get(newCtx, &application2.ApplicationQuery{Name: &argoAppName, Refresh: &refreshType}) +func (impl *ArgoClientWrapperServiceImpl) ResourceTree(ctxt context.Context, query *application2.ResourcesQuery) (*v1alpha1.ApplicationTree, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() if err != nil { - internalMsg := fmt.Sprintf("%s, err:- %s", constants.CannotGetAppWithRefreshErrMsg, err.Error()) - clientCode, _ := util.GetClientDetailedError(err) - httpStatusCode := clientCode.GetHttpStatusCodeForGivenGrpcCode() - err = &util.ApiError{HttpStatusCode: httpStatusCode, Code: strconv.Itoa(httpStatusCode), InternalMessage: internalMsg, UserMessage: err.Error()} - impl.logger.Errorw("cannot get application with refresh", "app", argoAppName) - return err + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, nil } - impl.logger.Debugw("done getting the application with refresh with no error", "argoAppName", argoAppName) - return nil + return impl.acdApplicationClient.ResourceTree(ctxt, grpcConfig, query) +} + +func (impl *ArgoClientWrapperServiceImpl) GetArgoClient(ctxt context.Context) (application2.ApplicationServiceClient, *grpc.ClientConn, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, nil, err + } + return impl.acdApplicationClient.GetArgoClient(ctxt, grpcConfig) +} + +func (impl *ArgoClientWrapperServiceImpl) GetApplicationResource(ctx context.Context, query *application2.ApplicationResourceRequest) (*application2.ApplicationResourceResponse, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, err + } + resource, err := impl.acdApplicationClient.GetResource(ctx, grpcConfig, query) + if err != nil { + impl.logger.Errorw("error in getting resource", "err", err) + return nil, err + } + return resource, nil +} + +func (impl *ArgoClientWrapperServiceImpl) GetArgoApplication(ctx context.Context, query *application2.ApplicationQuery) (*v1alpha1.Application, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, err + } + return impl.acdApplicationClient.Get(ctx, grpcConfig, query) +} + +func (impl *ArgoClientWrapperServiceImpl) DeleteArgoApp(ctx context.Context, appName string, cascadeDelete bool) (*application2.ApplicationResponse, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, err + } + req := &application2.ApplicationDeleteRequest{ + Name: &appName, + Cascade: &cascadeDelete, + } + return impl.acdApplicationClient.Delete(ctx, grpcConfig, req) } func (impl *ArgoClientWrapperServiceImpl) SyncArgoCDApplicationIfNeededAndRefresh(ctx context.Context, argoAppName string) error { newCtx, span := otel.Tracer("orchestrator").Start(ctx, "ArgoClientWrapperServiceImpl.SyncArgoCDApplicationIfNeededAndRefresh") defer span.End() impl.logger.Info("ArgoCd manual sync for app started", "argoAppName", argoAppName) + + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return err + } + if impl.ACDConfig.IsManualSyncEnabled() { impl.logger.Debugw("syncing ArgoCd app as manual sync is enabled", "argoAppName", argoAppName) revision := "master" pruneResources := true - _, syncErr := impl.acdClient.Sync(newCtx, &application2.ApplicationSyncRequest{Name: &argoAppName, + _, syncErr := impl.acdApplicationClient.Sync(newCtx, grpcConfig, &application2.ApplicationSyncRequest{Name: &argoAppName, Revision: &revision, Prune: &pruneResources, }) @@ -158,14 +260,14 @@ func (impl *ArgoClientWrapperServiceImpl) SyncArgoCDApplicationIfNeededAndRefres statusCode, msg := util.GetClientDetailedError(syncErr) if statusCode.IsFailedPreconditionCode() && msg == ErrorOperationAlreadyInProgress { impl.logger.Info("terminating ongoing sync operation and retrying manual sync", "argoAppName", argoAppName) - _, terminationErr := impl.acdClient.TerminateOperation(newCtx, &application2.OperationTerminateRequest{ + _, terminationErr := impl.acdApplicationClient.TerminateOperation(newCtx, grpcConfig, &application2.OperationTerminateRequest{ Name: &argoAppName, }) if terminationErr != nil { impl.logger.Errorw("error in terminating sync operation") return fmt.Errorf("error in terminating existing sync, err: %w", terminationErr) } - _, syncErr = impl.acdClient.Sync(newCtx, &application2.ApplicationSyncRequest{Name: &argoAppName, + _, syncErr = impl.acdApplicationClient.Sync(newCtx, grpcConfig, &application2.ApplicationSyncRequest{Name: &argoAppName, Revision: &revision, Prune: &pruneResources, RetryStrategy: &v1alpha1.RetryStrategy{ @@ -185,7 +287,7 @@ func (impl *ArgoClientWrapperServiceImpl) SyncArgoCDApplicationIfNeededAndRefres runnableFunc := func() { // running ArgoCd app refresh in asynchronous mode - refreshErr := impl.GetArgoAppWithNormalRefresh(context.Background(), argoAppName) + refreshErr := impl.GetArgoAppWithNormalRefresh(context.Background(), grpcConfig, argoAppName) if refreshErr != nil { impl.logger.Errorw("error in refreshing argo app", "argoAppName", argoAppName, "err", refreshErr) } @@ -194,11 +296,36 @@ func (impl *ArgoClientWrapperServiceImpl) SyncArgoCDApplicationIfNeededAndRefres return nil } +func (impl *ArgoClientWrapperServiceImpl) GetArgoAppWithNormalRefresh(ctx context.Context, grpcConfig *bean.ArgoGRPCConfig, argoAppName string) error { + newCtx, span := otel.Tracer("orchestrator").Start(ctx, "ArgoClientWrapperServiceImpl.GetArgoAppWithNormalRefresh") + defer span.End() + refreshType := bean.RefreshTypeNormal + impl.logger.Debugw("trying to normal refresh application through get ", "argoAppName", argoAppName) + _, err := impl.acdApplicationClient.Get(newCtx, grpcConfig, &application2.ApplicationQuery{Name: &argoAppName, Refresh: &refreshType}) + if err != nil { + internalMsg := fmt.Sprintf("%s, err:- %s", constants.CannotGetAppWithRefreshErrMsg, err.Error()) + clientCode, _ := util.GetClientDetailedError(err) + httpStatusCode := clientCode.GetHttpStatusCodeForGivenGrpcCode() + err = &util.ApiError{HttpStatusCode: httpStatusCode, Code: strconv.Itoa(httpStatusCode), InternalMessage: internalMsg, UserMessage: err.Error()} + impl.logger.Errorw("cannot get application with refresh", "app", argoAppName) + return err + } + impl.logger.Debugw("done getting the application with refresh with no error", "argoAppName", argoAppName) + return nil +} + func (impl *ArgoClientWrapperServiceImpl) UpdateArgoCDSyncModeIfNeeded(ctx context.Context, argoApplication *v1alpha1.Application) (err error) { - if impl.isArgoAppSyncModeMigrationNeeded(argoApplication) { - syncModeUpdateRequest := impl.CreateRequestForArgoCDSyncModeUpdateRequest(argoApplication) + if isArgoAppSyncModeMigrationNeeded(argoApplication, impl.ACDConfig) { + + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return err + } + + syncModeUpdateRequest := createRequestForArgoCDSyncModeUpdateRequest(argoApplication, impl.ACDConfig.IsAutoSyncEnabled()) validate := false - _, err = impl.acdClient.Update(ctx, &application2.ApplicationUpdateRequest{Application: syncModeUpdateRequest, Validate: &validate}) + _, err = impl.acdApplicationClient.Update(ctx, grpcConfig, &application2.ApplicationUpdateRequest{Application: syncModeUpdateRequest, Validate: &validate}) if err != nil { impl.logger.Errorw("error in creating argo pipeline ", "name", argoApplication.Name, "err", err) return err @@ -207,41 +334,16 @@ func (impl *ArgoClientWrapperServiceImpl) UpdateArgoCDSyncModeIfNeeded(ctx conte return nil } -func (impl *ArgoClientWrapperServiceImpl) isArgoAppSyncModeMigrationNeeded(argoApplication *v1alpha1.Application) bool { - if impl.ACDConfig.IsManualSyncEnabled() && argoApplication.Spec.SyncPolicy.Automated != nil { - return true - } else if impl.ACDConfig.IsAutoSyncEnabled() && argoApplication.Spec.SyncPolicy.Automated == nil { - return true - } - return false -} +func (impl *ArgoClientWrapperServiceImpl) RegisterGitOpsRepoInArgoWithRetry(ctx context.Context, gitOpsRepoUrl string, userId int32) error { -func (impl *ArgoClientWrapperServiceImpl) CreateRequestForArgoCDSyncModeUpdateRequest(argoApplication *v1alpha1.Application) *v1alpha1.Application { - // set automated field in update request - var automated *v1alpha1.SyncPolicyAutomated - if impl.ACDConfig.IsAutoSyncEnabled() { - automated = &v1alpha1.SyncPolicyAutomated{ - Prune: true, - } + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil } - return &v1alpha1.Application{ - ObjectMeta: v1.ObjectMeta{ - Name: argoApplication.Name, - Namespace: DevtronInstalationNs, - }, - Spec: v1alpha1.ApplicationSpec{ - Destination: argoApplication.Spec.Destination, - Source: argoApplication.Spec.Source, - SyncPolicy: &v1alpha1.SyncPolicy{ - Automated: automated, - SyncOptions: argoApplication.Spec.SyncPolicy.SyncOptions, - Retry: argoApplication.Spec.SyncPolicy.Retry, - }}} -} -func (impl *ArgoClientWrapperServiceImpl) RegisterGitOpsRepoInArgoWithRetry(ctx context.Context, gitOpsRepoUrl string, userId int32) error { callback := func() error { - return impl.createRepoInArgoCd(ctx, gitOpsRepoUrl) + return impl.createRepoInArgoCd(ctx, grpcConfig, gitOpsRepoUrl) } argoCdErr := retryFunc.Retry(callback, impl.isRetryableArgoRepoCreationError, @@ -250,14 +352,48 @@ func (impl *ArgoClientWrapperServiceImpl) RegisterGitOpsRepoInArgoWithRetry(ctx impl.logger) if argoCdErr != nil { impl.logger.Errorw("error in registering GitOps repository", "repoName", gitOpsRepoUrl, "err", argoCdErr) - return impl.handleArgoRepoCreationError(argoCdErr, ctx, gitOpsRepoUrl, userId) + return impl.handleArgoRepoCreationError(ctx, argoCdErr, grpcConfig, gitOpsRepoUrl, userId) } impl.logger.Infow("gitOps repo registered in argo", "repoName", gitOpsRepoUrl) return nil } +func (impl *ArgoClientWrapperServiceImpl) CreateRepoCreds(ctx context.Context, query *repocreds.RepoCredsCreateRequest) (*v1alpha1.RepoCreds, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, err + } + return impl.repoCredsClient.CreateRepoCreds(ctx, grpcConfig, query) +} + +func (impl *ArgoClientWrapperServiceImpl) AddOrUpdateOCIRegistry(username, password string, uniqueId int, registryUrl, repo string, isPublic bool) error { + return impl.ArgoClientWrapperServiceEAImpl.AddOrUpdateOCIRegistry(username, password, uniqueId, registryUrl, repo, isPublic) +} + +func (impl *ArgoClientWrapperServiceImpl) DeleteOCIRegistry(registryURL, repo string, ociRegistryId int) error { + return impl.ArgoClientWrapperServiceEAImpl.DeleteOCIRegistry(registryURL, repo, ociRegistryId) +} + +func (impl *ArgoClientWrapperServiceImpl) AddChartRepository(request bean2.ChartRepositoryAddRequest) error { + return impl.ArgoClientWrapperServiceEAImpl.AddChartRepository(request) +} + +func (impl *ArgoClientWrapperServiceImpl) UpdateChartRepository(request bean2.ChartRepositoryUpdateRequest) error { + return impl.ArgoClientWrapperServiceEAImpl.UpdateChartRepository(request) +} + +func (impl *ArgoClientWrapperServiceImpl) DeleteChartRepository(name, url string) error { + return impl.ArgoClientWrapperServiceEAImpl.DeleteChartRepository(name, url) +} + func (impl *ArgoClientWrapperServiceImpl) GetArgoAppByName(ctx context.Context, appName string) (*v1alpha1.Application, error) { - argoApplication, err := impl.acdClient.Get(ctx, &application2.ApplicationQuery{Name: &appName}) + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, err + } + argoApplication, err := impl.acdApplicationClient.Get(ctx, grpcConfig, &application2.ApplicationQuery{Name: &appName}) if err != nil { impl.logger.Errorw("err in getting argo app by name", "app", appName) return nil, err @@ -272,6 +408,13 @@ func (impl *ArgoClientWrapperServiceImpl) IsArgoAppPatchRequired(argoAppSpec *v1 } func (impl *ArgoClientWrapperServiceImpl) PatchArgoCdApp(ctx context.Context, dto *bean.ArgoCdAppPatchReqDto) error { + + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return err + } + patchReq := adapter.GetArgoCdPatchReqFromDto(dto) reqbyte, err := json.Marshal(patchReq) if err != nil { @@ -279,7 +422,7 @@ func (impl *ArgoClientWrapperServiceImpl) PatchArgoCdApp(ctx context.Context, dt return err } reqString := string(reqbyte) - _, err = impl.acdClient.Patch(ctx, &application2.ApplicationPatchRequest{Patch: &reqString, Name: &dto.ArgoAppName, PatchType: &dto.PatchType}) + _, err = impl.acdApplicationClient.Patch(ctx, grpcConfig, &application2.ApplicationPatchRequest{Patch: &reqString, Name: &dto.ArgoAppName, PatchType: &dto.PatchType}) if err != nil { impl.logger.Errorw("error in patching argo pipeline ", "name", dto.ArgoAppName, "patch", reqString, "err", err) return err @@ -287,8 +430,13 @@ func (impl *ArgoClientWrapperServiceImpl) PatchArgoCdApp(ctx context.Context, dt return nil } -func (impl *ArgoClientWrapperServiceImpl) GetGitOpsRepoName(ctx context.Context, appName string) (gitOpsRepoName string, err error) { - acdApplication, err := impl.acdClient.Get(ctx, &application2.ApplicationQuery{Name: &appName}) +func (impl *ArgoClientWrapperServiceImpl) GetGitOpsRepoNameForApplication(ctx context.Context, appName string) (gitOpsRepoName string, err error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return gitOpsRepoName, err + } + acdApplication, err := impl.acdApplicationClient.Get(ctx, grpcConfig, &application2.ApplicationQuery{Name: &appName}) if err != nil { impl.logger.Errorw("no argo app exists", "acdAppName", appName, "err", err) return gitOpsRepoName, err @@ -302,8 +450,13 @@ func (impl *ArgoClientWrapperServiceImpl) GetGitOpsRepoName(ctx context.Context, return gitOpsRepoName, fmt.Errorf("unable to get any ArgoCd application '%s'", appName) } -func (impl *ArgoClientWrapperServiceImpl) GetGitOpsRepoURL(ctx context.Context, appName string) (gitOpsRepoName string, err error) { - acdApplication, err := impl.acdClient.Get(ctx, &application2.ApplicationQuery{Name: &appName}) +func (impl *ArgoClientWrapperServiceImpl) GetGitOpsRepoURLForApplication(ctx context.Context, appName string) (gitOpsRepoName string, err error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return gitOpsRepoName, err + } + acdApplication, err := impl.acdApplicationClient.Get(ctx, grpcConfig, &application2.ApplicationQuery{Name: &appName}) if err != nil { impl.logger.Errorw("no argo app exists", "acdAppName", appName, "err", err) return gitOpsRepoName, err @@ -317,11 +470,11 @@ func (impl *ArgoClientWrapperServiceImpl) GetGitOpsRepoURL(ctx context.Context, } // createRepoInArgoCd is the wrapper function to Create Repository in ArgoCd -func (impl *ArgoClientWrapperServiceImpl) createRepoInArgoCd(ctx context.Context, gitOpsRepoUrl string) error { +func (impl *ArgoClientWrapperServiceImpl) createRepoInArgoCd(ctx context.Context, grpcConfig *bean.ArgoGRPCConfig, gitOpsRepoUrl string) error { repo := &v1alpha1.Repository{ Repo: gitOpsRepoUrl, } - repo, err := impl.repositoryService.Create(ctx, &repository2.RepoCreateRequest{Repo: repo, Upsert: true}) + repo, err := impl.repositoryService.Create(ctx, grpcConfig, &repository2.RepoCreateRequest{Repo: repo, Upsert: true}) if err != nil { impl.logger.Errorw("error in creating argo Repository", "err", err) return err @@ -336,7 +489,7 @@ func (impl *ArgoClientWrapperServiceImpl) isRetryableArgoRepoCreationError(argoC } // handleArgoRepoCreationError - manages the error thrown while performing createRepoInArgoCd -func (impl *ArgoClientWrapperServiceImpl) handleArgoRepoCreationError(argoCdErr error, ctx context.Context, gitOpsRepoUrl string, userId int32) error { +func (impl *ArgoClientWrapperServiceImpl) handleArgoRepoCreationError(ctx context.Context, argoCdErr error, grpcConfig *bean.ArgoGRPCConfig, gitOpsRepoUrl string, userId int32) error { emptyRepoErrorMessages := bean.EmptyRepoErrorList isEmptyRepoError := false for _, errMsg := range emptyRepoErrorMessages { @@ -354,5 +507,47 @@ func (impl *ArgoClientWrapperServiceImpl) handleArgoRepoCreationError(argoCdErr } } // try to register with after creating readme file - return impl.createRepoInArgoCd(ctx, gitOpsRepoUrl) + return impl.createRepoInArgoCd(ctx, grpcConfig, gitOpsRepoUrl) +} + +func (impl *ArgoClientWrapperServiceImpl) CreateCluster(ctx context.Context, clusterRequest *cluster2.ClusterCreateRequest) (*v1alpha1.Cluster, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, err + } + cluster, err := impl.clusterClient.Create(ctx, grpcConfig, clusterRequest) + if err != nil { + return nil, err + } + return cluster, nil +} + +func (impl *ArgoClientWrapperServiceImpl) UpdateCluster(ctx context.Context, clusterRequest *cluster2.ClusterUpdateRequest) (*v1alpha1.Cluster, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting grpc config", "err", err) + return nil, err + } + cluster, err := impl.clusterClient.Update(ctx, grpcConfig, clusterRequest) + if err != nil { + return nil, err + } + return cluster, nil +} + +func (impl *ArgoClientWrapperServiceImpl) CreateCertificate(ctx context.Context, query *certificate.RepositoryCertificateCreateRequest) (*v1alpha1.RepositoryCertificateList, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + return nil, err + } + return impl.CertificateClient.CreateCertificate(ctx, grpcConfig, query) +} + +func (impl *ArgoClientWrapperServiceImpl) DeleteCertificate(ctx context.Context, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { + grpcConfig, err := impl.acdConfigGetter.GetGRPCConfig() + if err != nil { + return nil, err + } + return impl.CertificateClient.DeleteCertificate(ctx, grpcConfig, query, opts...) } diff --git a/client/argocdServer/ArgoClientWrapperServiceEA.go b/client/argocdServer/ArgoClientWrapperServiceEA.go new file mode 100644 index 0000000000..b272649ff4 --- /dev/null +++ b/client/argocdServer/ArgoClientWrapperServiceEA.go @@ -0,0 +1,164 @@ +package argocdServer + +import ( + "context" + application2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" + "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate" + cluster2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster" + "github.com/argoproj/argo-cd/v2/pkg/apiclient/repocreds" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/devtron-labs/devtron/client/argocdServer/bean" + config2 "github.com/devtron-labs/devtron/client/argocdServer/config" + "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient" + bean2 "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient/bean" + "go.uber.org/zap" + "google.golang.org/grpc" +) + +type ArgoClientWrapperServiceEAImpl struct { + logger *zap.SugaredLogger + repoCredsK8sClient repoCredsK8sClient.RepositoryCredsK8sClient + acdConfigGetter config2.ArgoCDConfigGetter +} + +func NewArgoClientWrapperServiceEAImpl( + logger *zap.SugaredLogger, + repoCredsK8sClient repoCredsK8sClient.RepositoryCredsK8sClient, + acdConfigGetter config2.ArgoCDConfigGetter, +) *ArgoClientWrapperServiceEAImpl { + return &ArgoClientWrapperServiceEAImpl{ + logger: logger, + repoCredsK8sClient: repoCredsK8sClient, + acdConfigGetter: acdConfigGetter, + } +} + +func (impl *ArgoClientWrapperServiceEAImpl) ResourceTree(ctxt context.Context, query *application2.ResourcesQuery) (*v1alpha1.ApplicationTree, error) { + impl.logger.Info("not implemented") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) GetArgoClient(ctxt context.Context) (application2.ApplicationServiceClient, *grpc.ClientConn, error) { + impl.logger.Info("not implemented") + return nil, nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) GetApplicationResource(ctx context.Context, query *application2.ApplicationResourceRequest) (*application2.ApplicationResourceResponse, error) { + impl.logger.Info("not implemented") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) GetArgoApplication(ctx context.Context, query *application2.ApplicationQuery) (*v1alpha1.Application, error) { + impl.logger.Info("not implemented") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) DeleteArgoApp(ctx context.Context, appName string, cascadeDelete bool) (*application2.ApplicationResponse, error) { + impl.logger.Info("not implemented") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) SyncArgoCDApplicationIfNeededAndRefresh(ctx context.Context, argoAppName string) error { + impl.logger.Info("not implemented") + return nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) UpdateArgoCDSyncModeIfNeeded(ctx context.Context, argoApplication *v1alpha1.Application) (err error) { + impl.logger.Info("not implemented") + return nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) RegisterGitOpsRepoInArgoWithRetry(ctx context.Context, gitOpsRepoUrl string, userId int32) error { + impl.logger.Info("not implemented") + return nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) CreateRepoCreds(ctx context.Context, query *repocreds.RepoCredsCreateRequest) (*v1alpha1.RepoCreds, error) { + impl.logger.Info("not implemented") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) AddOrUpdateOCIRegistry(username, password string, uniqueId int, registryUrl, repo string, isPublic bool) error { + argoK8sConfig, err := impl.acdConfigGetter.GetK8sConfig() + if err != nil { + impl.logger.Errorw("error in getting k8s config", "err", err) + } + return impl.repoCredsK8sClient.AddOrUpdateOCIRegistry(argoK8sConfig, username, password, uniqueId, registryUrl, repo, isPublic) +} + +func (impl *ArgoClientWrapperServiceEAImpl) DeleteOCIRegistry(registryURL, repo string, ociRegistryId int) error { + argoK8sConfig, err := impl.acdConfigGetter.GetK8sConfig() + if err != nil { + impl.logger.Errorw("error in getting k8s config", "err", err) + } + return impl.repoCredsK8sClient.DeleteOCIRegistry(argoK8sConfig, registryURL, repo, ociRegistryId) +} + +func (impl *ArgoClientWrapperServiceEAImpl) AddChartRepository(request bean2.ChartRepositoryAddRequest) error { + argoK8sConfig, err := impl.acdConfigGetter.GetK8sConfig() + if err != nil { + impl.logger.Errorw("error in getting k8s config", "err", err) + } + return impl.repoCredsK8sClient.AddChartRepository(argoK8sConfig, request) +} + +func (impl *ArgoClientWrapperServiceEAImpl) UpdateChartRepository(request bean2.ChartRepositoryUpdateRequest) error { + argoK8sConfig, err := impl.acdConfigGetter.GetK8sConfig() + if err != nil { + return err + } + return impl.repoCredsK8sClient.UpdateChartRepository(argoK8sConfig, request) +} + +func (impl *ArgoClientWrapperServiceEAImpl) DeleteChartRepository(name, url string) error { + argoK8sConfig, err := impl.acdConfigGetter.GetK8sConfig() + if err != nil { + return err + } + return impl.repoCredsK8sClient.DeleteChartRepository(argoK8sConfig, name, url) +} + +func (impl *ArgoClientWrapperServiceEAImpl) GetArgoAppByName(ctx context.Context, appName string) (*v1alpha1.Application, error) { + impl.logger.Info("not implemented for EA mode") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) IsArgoAppPatchRequired(argoAppSpec *v1alpha1.ApplicationSource, currentGitRepoUrl, currentChartPath string) bool { + impl.logger.Info("not implemented for EA mode") + return false +} + +func (impl *ArgoClientWrapperServiceEAImpl) PatchArgoCdApp(ctx context.Context, dto *bean.ArgoCdAppPatchReqDto) error { + impl.logger.Info("not implemented for EA mode") + return nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) GetGitOpsRepoNameForApplication(ctx context.Context, appName string) (gitOpsRepoName string, err error) { + impl.logger.Info("not implemented for EA mode") + return "", nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) GetGitOpsRepoURLForApplication(ctx context.Context, appName string) (gitOpsRepoName string, err error) { + impl.logger.Info("not implemented for EA mode") + return "", nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) CreateCluster(ctx context.Context, clusterRequest *cluster2.ClusterCreateRequest) (*v1alpha1.Cluster, error) { + impl.logger.Info("not implemented for EA mode") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) UpdateCluster(ctx context.Context, clusterRequest *cluster2.ClusterUpdateRequest) (*v1alpha1.Cluster, error) { + impl.logger.Info("not implemented for EA mode") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) CreateCertificate(ctx context.Context, query *certificate.RepositoryCertificateCreateRequest) (*v1alpha1.RepositoryCertificateList, error) { + impl.logger.Info("not implemented for EA mode") + return nil, nil +} + +func (impl *ArgoClientWrapperServiceEAImpl) DeleteCertificate(ctx context.Context, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { + impl.logger.Info("not implemented for EA mode") + return nil, nil +} diff --git a/client/argocdServer/application/Application.go b/client/argocdServer/application/Application.go index ffc2908b17..5c54d826a1 100644 --- a/client/argocdServer/application/Application.go +++ b/client/argocdServer/application/Application.go @@ -28,30 +28,30 @@ import ( ) type ServiceClient interface { - ResourceTree(ctxt context.Context, query *application.ResourcesQuery) (*v1alpha1.ApplicationTree, error) + ResourceTree(ctxt context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ResourcesQuery) (*v1alpha1.ApplicationTree, error) // GetArgoClient return argo connection client - GetArgoClient(ctxt context.Context) (application.ApplicationServiceClient, *grpc.ClientConn, error) + GetArgoClient(ctxt context.Context, grpcConfig *argoApplication.ArgoGRPCConfig) (application.ApplicationServiceClient, *grpc.ClientConn, error) // Patch an ArgoCd application - Patch(ctx context.Context, query *application.ApplicationPatchRequest) (*v1alpha1.Application, error) + Patch(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationPatchRequest) (*v1alpha1.Application, error) // GetResource returns single application resource - GetResource(ctxt context.Context, query *application.ApplicationResourceRequest) (*application.ApplicationResourceResponse, error) + GetResource(ctxt context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationResourceRequest) (*application.ApplicationResourceResponse, error) // Get returns an application by name - Get(ctx context.Context, query *application.ApplicationQuery) (*v1alpha1.Application, error) + Get(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationQuery) (*v1alpha1.Application, error) // Update updates an application - Update(ctx context.Context, query *application.ApplicationUpdateRequest) (*v1alpha1.Application, error) + Update(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationUpdateRequest) (*v1alpha1.Application, error) // Sync syncs an application to its target state - Sync(ctx context.Context, query *application.ApplicationSyncRequest) (*v1alpha1.Application, error) + Sync(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationSyncRequest) (*v1alpha1.Application, error) // Delete deletes an application - Delete(ctx context.Context, query *application.ApplicationDeleteRequest) (*application.ApplicationResponse, error) + Delete(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationDeleteRequest) (*application.ApplicationResponse, error) - TerminateOperation(ctx context.Context, query *application.OperationTerminateRequest) (*application.OperationTerminateResponse, error) + TerminateOperation(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.OperationTerminateRequest) (*application.OperationTerminateResponse, error) } type ServiceClientImpl struct { @@ -68,14 +68,18 @@ func NewApplicationClientImpl( } } -func (c *ServiceClientImpl) GetArgoClient(ctxt context.Context) (application.ApplicationServiceClient, *grpc.ClientConn, error) { - conn := c.argoCDConnectionManager.GetConnection() - asc := application.NewApplicationServiceClient(conn) - return asc, conn, nil +func (c ServiceClientImpl) getService(connectionConfig *argoApplication.ArgoGRPCConfig) (application.ApplicationServiceClient, *grpc.ClientConn, error) { + conn := c.argoCDConnectionManager.GetGrpcClientConnection(connectionConfig) + //defer conn.Close() + return application.NewApplicationServiceClient(conn), conn, nil } -func (c *ServiceClientImpl) ResourceTree(ctxt context.Context, query *application.ResourcesQuery) (*v1alpha1.ApplicationTree, error) { - asc, conn, err := c.GetArgoClient(ctxt) +func (c *ServiceClientImpl) GetArgoClient(ctxt context.Context, grpcConfig *argoApplication.ArgoGRPCConfig) (application.ApplicationServiceClient, *grpc.ClientConn, error) { + return c.getService(grpcConfig) +} + +func (c *ServiceClientImpl) ResourceTree(ctxt context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ResourcesQuery) (*v1alpha1.ApplicationTree, error) { + asc, conn, err := c.GetArgoClient(ctxt, grpcConfig) if err != nil { c.logger.Errorw("error getting ArgoCD client", "error", err) return nil, err @@ -90,10 +94,10 @@ func (c *ServiceClientImpl) ResourceTree(ctxt context.Context, query *applicatio return resp, nil } -func (c ServiceClientImpl) Patch(ctxt context.Context, query *application.ApplicationPatchRequest) (*v1alpha1.Application, error) { - ctx, cancel := context.WithTimeout(ctxt, argoApplication.TimeoutLazy) +func (c ServiceClientImpl) Patch(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationPatchRequest) (*v1alpha1.Application, error) { + ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutLazy) defer cancel() - asc, conn, err := c.GetArgoClient(ctxt) + asc, conn, err := c.GetArgoClient(ctx, grpcConfig) if err != nil { c.logger.Errorw("error getting ArgoCD client", "error", err) return nil, err @@ -103,11 +107,11 @@ func (c ServiceClientImpl) Patch(ctxt context.Context, query *application.Applic return resp, err } -func (c ServiceClientImpl) Get(ctx context.Context, query *application.ApplicationQuery) (*v1alpha1.Application, error) { +func (c ServiceClientImpl) Get(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationQuery) (*v1alpha1.Application, error) { newCtx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutFast) defer cancel() - asc, conn, err := c.GetArgoClient(ctx) + asc, conn, err := c.GetArgoClient(ctx, grpcConfig) if err != nil { c.logger.Errorw("error getting ArgoCD client", "error", err) return nil, err @@ -117,10 +121,10 @@ func (c ServiceClientImpl) Get(ctx context.Context, query *application.Applicati return resp, err } -func (c ServiceClientImpl) Update(ctxt context.Context, query *application.ApplicationUpdateRequest) (*v1alpha1.Application, error) { - ctx, cancel := context.WithTimeout(ctxt, argoApplication.TimeoutFast) +func (c ServiceClientImpl) Update(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationUpdateRequest) (*v1alpha1.Application, error) { + ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutFast) defer cancel() - asc, conn, err := c.GetArgoClient(ctx) + asc, conn, err := c.GetArgoClient(ctx, grpcConfig) if err != nil { c.logger.Errorw("error getting ArgoCD client", "error", err) return nil, err @@ -130,10 +134,10 @@ func (c ServiceClientImpl) Update(ctxt context.Context, query *application.Appli return resp, err } -func (c ServiceClientImpl) Sync(ctxt context.Context, query *application.ApplicationSyncRequest) (*v1alpha1.Application, error) { - ctx, cancel := context.WithTimeout(ctxt, argoApplication.TimeoutFast) +func (c ServiceClientImpl) Sync(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationSyncRequest) (*v1alpha1.Application, error) { + ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutFast) defer cancel() - asc, conn, err := c.GetArgoClient(ctx) + asc, conn, err := c.GetArgoClient(ctx, grpcConfig) if err != nil { c.logger.Errorw("error getting ArgoCD client", "error", err) return nil, err @@ -143,10 +147,10 @@ func (c ServiceClientImpl) Sync(ctxt context.Context, query *application.Applica return resp, err } -func (c ServiceClientImpl) GetResource(ctxt context.Context, query *application.ApplicationResourceRequest) (*application.ApplicationResourceResponse, error) { +func (c ServiceClientImpl) GetResource(ctxt context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationResourceRequest) (*application.ApplicationResourceResponse, error) { ctx, cancel := context.WithTimeout(ctxt, argoApplication.TimeoutFast) defer cancel() - asc, conn, err := c.GetArgoClient(ctx) + asc, conn, err := c.GetArgoClient(ctx, grpcConfig) if err != nil { c.logger.Errorw("error getting ArgoCD client", "error", err) return nil, err @@ -155,10 +159,10 @@ func (c ServiceClientImpl) GetResource(ctxt context.Context, query *application. return asc.GetResource(ctx, query) } -func (c ServiceClientImpl) Delete(ctxt context.Context, query *application.ApplicationDeleteRequest) (*application.ApplicationResponse, error) { - ctx, cancel := context.WithTimeout(ctxt, argoApplication.TimeoutSlow) +func (c ServiceClientImpl) Delete(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.ApplicationDeleteRequest) (*application.ApplicationResponse, error) { + ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutSlow) defer cancel() - asc, conn, err := c.GetArgoClient(ctx) + asc, conn, err := c.GetArgoClient(ctx, grpcConfig) if err != nil { c.logger.Errorw("error getting ArgoCD client", "error", err) return nil, err @@ -166,10 +170,10 @@ func (c ServiceClientImpl) Delete(ctxt context.Context, query *application.Appli defer util.Close(conn, c.logger) return asc.Delete(ctx, query) } -func (c ServiceClientImpl) TerminateOperation(ctxt context.Context, query *application.OperationTerminateRequest) (*application.OperationTerminateResponse, error) { - ctx, cancel := context.WithTimeout(ctxt, argoApplication.TimeoutFast) +func (c ServiceClientImpl) TerminateOperation(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *application.OperationTerminateRequest) (*application.OperationTerminateResponse, error) { + ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutFast) defer cancel() - asc, conn, err := c.GetArgoClient(ctx) + asc, conn, err := c.GetArgoClient(ctx, grpcConfig) if err != nil { c.logger.Errorw("error getting ArgoCD client", "error", err) return nil, err diff --git a/client/argocdServer/bean/bean.go b/client/argocdServer/bean/bean.go index 1493b5e56a..78b07d8aad 100644 --- a/client/argocdServer/bean/bean.go +++ b/client/argocdServer/bean/bean.go @@ -99,11 +99,3 @@ func NewErrUnauthorized(message string) *ErrUnauthorized { func (e *ErrUnauthorized) Error() string { return e.message } - -type AcdAuthConfig struct { - ClusterId int - DevtronSecretName string - DevtronDexSecretNamespace string - UserName string - Password string -} diff --git a/client/argocdServer/bean/connection.go b/client/argocdServer/bean/connection.go new file mode 100644 index 0000000000..320c233a3f --- /dev/null +++ b/client/argocdServer/bean/connection.go @@ -0,0 +1,37 @@ +package bean + +import ( + "github.com/caarlos0/env/v6" + "k8s.io/client-go/rest" +) + +type ArgoGRPCConfig struct { + ConnectionConfig *Config + AuthConfig *AcdAuthConfig +} + +type ArgoK8sConfig struct { + RestConfig *rest.Config + AcdNamespace string + AcdConfigMapName string +} + +type AcdAuthConfig struct { + ClusterId int + DevtronSecretName string + DevtronDexSecretNamespace string + UserName string + Password string +} + +type Config struct { + Host string `env:"CD_HOST" envDefault:"localhost"` + Port string `env:"CD_PORT" envDefault:"8000"` + Namespace string `env:"CD_NAMESPACE" envDefault:"devtroncd"` +} + +func GetConfig() (*Config, error) { + cfg := &Config{} + err := env.Parse(cfg) + return cfg, err +} diff --git a/client/argocdServer/certificate/Certificate.go b/client/argocdServer/certificate/Certificate.go index de8f5d8381..984c32b56f 100644 --- a/client/argocdServer/certificate/Certificate.go +++ b/client/argocdServer/certificate/Certificate.go @@ -4,16 +4,16 @@ import ( "context" "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/client/argocdServer/connection" "go.uber.org/zap" "google.golang.org/grpc" "time" ) -type Client interface { - ListCertificates(ctx context.Context, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) - CreateCertificate(ctx context.Context, query *certificate.RepositoryCertificateCreateRequest) (*v1alpha1.RepositoryCertificateList, error) - DeleteCertificate(ctx context.Context, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) +type ServiceClient interface { + CreateCertificate(ctx context.Context, grpcConfig *bean.ArgoGRPCConfig, query *certificate.RepositoryCertificateCreateRequest) (*v1alpha1.RepositoryCertificateList, error) + DeleteCertificate(ctx context.Context, grpcConfig *bean.ArgoGRPCConfig, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) } type ServiceClientImpl struct { @@ -30,37 +30,26 @@ func NewServiceClientImpl( } } -func (c *ServiceClientImpl) getService(ctx context.Context) (certificate.CertificateServiceClient, error) { - - conn := c.argoCDConnectionManager.GetConnection() +func (c *ServiceClientImpl) getService(ctx context.Context, grpcConfig *bean.ArgoGRPCConfig) (certificate.CertificateServiceClient, error) { + conn := c.argoCDConnectionManager.GetGrpcClientConnection(grpcConfig) //defer conn.Close() return certificate.NewCertificateServiceClient(conn), nil } -func (c *ServiceClientImpl) ListCertificates(ctx context.Context, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { - ctx, cancel := context.WithTimeout(ctx, 10*time.Second) - defer cancel() - client, err := c.getService(ctx) - if err != nil { - return nil, err - } - return client.ListCertificates(ctx, query) -} - -func (c *ServiceClientImpl) CreateCertificate(ctx context.Context, query *certificate.RepositoryCertificateCreateRequest) (*v1alpha1.RepositoryCertificateList, error) { +func (c *ServiceClientImpl) CreateCertificate(ctx context.Context, grpcConfig *bean.ArgoGRPCConfig, query *certificate.RepositoryCertificateCreateRequest) (*v1alpha1.RepositoryCertificateList, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - client, err := c.getService(ctx) + client, err := c.getService(ctx, grpcConfig) if err != nil { return nil, err } return client.CreateCertificate(ctx, query) } -func (c *ServiceClientImpl) DeleteCertificate(ctx context.Context, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { +func (c *ServiceClientImpl) DeleteCertificate(ctx context.Context, grpcConfig *bean.ArgoGRPCConfig, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - client, err := c.getService(ctx) + client, err := c.getService(ctx, grpcConfig) if err != nil { return nil, err } diff --git a/client/argocdServer/cluster/Cluster.go b/client/argocdServer/cluster/Cluster.go index 0d64dd183b..e854e2e8eb 100644 --- a/client/argocdServer/cluster/Cluster.go +++ b/client/argocdServer/cluster/Cluster.go @@ -20,6 +20,7 @@ import ( "context" "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/client/argocdServer/connection" "go.uber.org/zap" "time" @@ -27,17 +28,17 @@ import ( type ServiceClient interface { // List returns list of clusters - List(ctx context.Context, query *cluster.ClusterQuery) (*v1alpha1.ClusterList, error) + List(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterQuery) (*v1alpha1.ClusterList, error) // Create creates a cluster - Create(ctx context.Context, query *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) + Create(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) // CreateFromKubeConfig installs the argocd-manager service account into the cluster specified in the given kubeconfig and context - CreateFromKubeConfig(ctx context.Context, query *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) + CreateFromKubeConfig(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) // Get returns a cluster by server address - Get(ctx context.Context, query *cluster.ClusterQuery) (*v1alpha1.Cluster, error) + Get(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterQuery) (*v1alpha1.Cluster, error) // Update updates a cluster - Update(ctx context.Context, query *cluster.ClusterUpdateRequest) (*v1alpha1.Cluster, error) + Update(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterUpdateRequest) (*v1alpha1.Cluster, error) // Delete deletes a cluster - Delete(ctx context.Context, query *cluster.ClusterQuery) (*cluster.ClusterResponse, error) + Delete(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterQuery) (*cluster.ClusterResponse, error) } type ServiceClientImpl struct { @@ -52,66 +53,66 @@ func NewServiceClientImpl(logger *zap.SugaredLogger, argoCdConnection connection } } -func (c ServiceClientImpl) getService(ctx context.Context) (cluster.ClusterServiceClient, error) { - conn := c.argoCdConnection.GetConnection() +func (c ServiceClientImpl) getService(connectionConfig *bean.ArgoGRPCConfig) (cluster.ClusterServiceClient, error) { + conn := c.argoCdConnection.GetGrpcClientConnection(connectionConfig) //defer conn.Close() return cluster.NewClusterServiceClient(conn), nil } -func (c ServiceClientImpl) List(ctx context.Context, query *cluster.ClusterQuery) (*v1alpha1.ClusterList, error) { +func (c ServiceClientImpl) List(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterQuery) (*v1alpha1.ClusterList, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - client, err := c.getService(ctx) + client, err := c.getService(connectionConfig) if err != nil { return nil, err } return client.List(ctx, query) } -func (c ServiceClientImpl) Create(ctx context.Context, query *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) { +func (c ServiceClientImpl) Create(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) { ctx, cancel := context.WithTimeout(ctx, 60*time.Second) defer cancel() - client, err := c.getService(ctx) + client, err := c.getService(connectionConfig) if err != nil { return nil, err } return client.Create(ctx, query) } -func (c ServiceClientImpl) CreateFromKubeConfig(ctx context.Context, query *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) { +func (c ServiceClientImpl) CreateFromKubeConfig(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) { ctx, cancel := context.WithTimeout(ctx, 60*time.Second) defer cancel() - client, err := c.getService(ctx) + client, err := c.getService(connectionConfig) if err != nil { return nil, err } return client.Create(ctx, query) } -func (c ServiceClientImpl) Get(ctx context.Context, query *cluster.ClusterQuery) (*v1alpha1.Cluster, error) { +func (c ServiceClientImpl) Get(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterQuery) (*v1alpha1.Cluster, error) { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - client, err := c.getService(ctx) + client, err := c.getService(connectionConfig) if err != nil { return nil, err } return client.Get(ctx, query) } -func (c ServiceClientImpl) Update(ctx context.Context, query *cluster.ClusterUpdateRequest) (*v1alpha1.Cluster, error) { +func (c ServiceClientImpl) Update(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterUpdateRequest) (*v1alpha1.Cluster, error) { ctx, cancel := context.WithTimeout(ctx, 60*time.Second) defer cancel() - client, err := c.getService(ctx) + client, err := c.getService(connectionConfig) if err != nil { return nil, err } return client.Update(ctx, query) } -func (c ServiceClientImpl) Delete(ctx context.Context, query *cluster.ClusterQuery) (*cluster.ClusterResponse, error) { +func (c ServiceClientImpl) Delete(ctx context.Context, connectionConfig *bean.ArgoGRPCConfig, query *cluster.ClusterQuery) (*cluster.ClusterResponse, error) { ctx, cancel := context.WithTimeout(ctx, 60*time.Second) defer cancel() - client, err := c.getService(ctx) + client, err := c.getService(connectionConfig) if err != nil { return nil, err } diff --git a/client/argocdServer/config/Config.go b/client/argocdServer/config/Config.go new file mode 100644 index 0000000000..55cb131621 --- /dev/null +++ b/client/argocdServer/config/Config.go @@ -0,0 +1,90 @@ +/* + * 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 config + +import ( + k8sUtil "github.com/devtron-labs/common-lib/utils/k8s" + "github.com/devtron-labs/devtron/client/argocdServer/bean" + bean2 "github.com/devtron-labs/devtron/pkg/cluster/bean" + "github.com/devtron-labs/devtron/pkg/cluster/read" + "github.com/devtron-labs/devtron/pkg/util" + util2 "github.com/devtron-labs/devtron/util" + "go.uber.org/zap" +) + +type ArgoCDConfigGetter interface { + GetGRPCConfig() (*bean.ArgoGRPCConfig, error) + GetK8sConfig() (*bean.ArgoK8sConfig, error) +} + +type ArgoCDConfigGetterImpl struct { + config *bean.Config + devtronSecretConfig *util2.DevtronSecretConfig + ACDAuthConfig *util.ACDAuthConfig + clusterReadService read.ClusterReadService + logger *zap.SugaredLogger + K8sService k8sUtil.K8sService +} + +func NewArgoCDConfigGetter( + config *bean.Config, + environmentVariables *util2.EnvironmentVariables, + ACDAuthConfig *util.ACDAuthConfig, + clusterReadService read.ClusterReadService, + logger *zap.SugaredLogger, + K8sService k8sUtil.K8sService, +) *ArgoCDConfigGetterImpl { + return &ArgoCDConfigGetterImpl{ + config: config, + devtronSecretConfig: environmentVariables.DevtronSecretConfig, + ACDAuthConfig: ACDAuthConfig, + clusterReadService: clusterReadService, + logger: logger, + K8sService: K8sService, + } +} + +func (impl *ArgoCDConfigGetterImpl) GetGRPCConfig() (*bean.ArgoGRPCConfig, error) { + return &bean.ArgoGRPCConfig{ + ConnectionConfig: impl.config, + AuthConfig: &bean.AcdAuthConfig{ + ClusterId: bean2.DefaultClusterId, + DevtronSecretName: impl.devtronSecretConfig.DevtronSecretName, + DevtronDexSecretNamespace: impl.devtronSecretConfig.DevtronDexSecretNamespace, + }, + }, nil +} + +func (impl *ArgoCDConfigGetterImpl) GetK8sConfig() (*bean.ArgoK8sConfig, error) { + clusterBean, err := impl.clusterReadService.FindOne(bean2.DEFAULT_CLUSTER) + if err != nil { + impl.logger.Errorw("error in fetching cluster bean from db", "err", err) + return nil, err + } + cfg := clusterBean.GetClusterConfig() + restConfig, err := impl.K8sService.GetRestConfigByCluster(cfg) + if err != nil { + impl.logger.Errorw("error in getting k8s config", "err", err) + return nil, err + } + k8sConfig := &bean.ArgoK8sConfig{ + RestConfig: restConfig, + AcdNamespace: impl.ACDAuthConfig.ACDConfigMapNamespace, + AcdConfigMapName: impl.ACDAuthConfig.ACDConfigMapName, + } + return k8sConfig, nil +} diff --git a/client/argocdServer/connection/Connection.go b/client/argocdServer/connection/Connection.go index feada44886..a3779763d5 100644 --- a/client/argocdServer/connection/Connection.go +++ b/client/argocdServer/connection/Connection.go @@ -23,6 +23,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/settings" "github.com/devtron-labs/common-lib/utils/k8s" "github.com/devtron-labs/devtron/client/argocdServer/bean" + config2 "github.com/devtron-labs/devtron/client/argocdServer/config" "github.com/devtron-labs/devtron/client/argocdServer/session" "github.com/devtron-labs/devtron/client/argocdServer/version" bean2 "github.com/devtron-labs/devtron/pkg/cluster/bean" @@ -63,8 +64,8 @@ const ( ) type ArgoCDConnectionManager interface { - GetConnection() *grpc.ClientConn - GetOrUpdateArgoCdUserDetail() string + GetGrpcClientConnection(grpcConfig *bean.ArgoGRPCConfig) *grpc.ClientConn + GetOrUpdateArgoCdUserDetail(grpcConfig *bean.ArgoGRPCConfig) string } type ArgoCDConnectionManagerImpl struct { logger *zap.SugaredLogger @@ -77,16 +78,19 @@ type ArgoCDConnectionManagerImpl struct { versionService version.VersionService gitOpsConfigReadService config.GitOpsConfigReadService runTimeConfig *k8s.RuntimeConfig + argoCDConfigGetter config2.ArgoCDConfigGetter } -func NewArgoCDConnectionManagerImpl(Logger *zap.SugaredLogger, settingsManager *settings.SettingsManager, +func NewArgoCDConnectionManagerImpl(Logger *zap.SugaredLogger, + settingsManager *settings.SettingsManager, moduleRepository moduleRepo.ModuleRepository, environmentVariables *util2.EnvironmentVariables, k8sUtil *k8s.K8sServiceImpl, k8sCommonService k8s2.K8sCommonService, versionService version.VersionService, gitOpsConfigReadService config.GitOpsConfigReadService, - runTimeConfig *k8s.RuntimeConfig) (*ArgoCDConnectionManagerImpl, error) { + runTimeConfig *k8s.RuntimeConfig, + argoCDConfigGetter config2.ArgoCDConfigGetter) (*ArgoCDConnectionManagerImpl, error) { argoUserServiceImpl := &ArgoCDConnectionManagerImpl{ logger: Logger, settingsManager: settingsManager, @@ -98,9 +102,14 @@ func NewArgoCDConnectionManagerImpl(Logger *zap.SugaredLogger, settingsManager * versionService: versionService, gitOpsConfigReadService: gitOpsConfigReadService, runTimeConfig: runTimeConfig, + argoCDConfigGetter: argoCDConfigGetter, } if !runTimeConfig.LocalDevMode { - go argoUserServiceImpl.ValidateGitOpsAndGetOrUpdateArgoCdUserDetail() + grpcConfig, err := argoCDConfigGetter.GetGRPCConfig() + if err != nil { + Logger.Errorw("error in GetAllGRPCConfigs", "error", err) + } + go argoUserServiceImpl.ValidateGitOpsAndGetOrUpdateArgoCdUserDetail(grpcConfig) } return argoUserServiceImpl, nil } @@ -110,36 +119,27 @@ const ( ModuleStatusInstalled string = "installed" ) -func (impl *ArgoCDConnectionManagerImpl) ValidateGitOpsAndGetOrUpdateArgoCdUserDetail() string { +func (impl *ArgoCDConnectionManagerImpl) ValidateGitOpsAndGetOrUpdateArgoCdUserDetail(grpcConfig *bean.ArgoGRPCConfig) string { gitOpsConfigurationStatus, err := impl.gitOpsConfigReadService.IsGitOpsConfigured() if err != nil || !gitOpsConfigurationStatus.IsGitOpsConfigured { return "" } - return impl.GetOrUpdateArgoCdUserDetail() + _ = impl.GetOrUpdateArgoCdUserDetail(grpcConfig) + return "" } // GetConnection - this function will call only for acd connection -func (impl *ArgoCDConnectionManagerImpl) GetConnection() *grpc.ClientConn { +func (impl *ArgoCDConnectionManagerImpl) GetGrpcClientConnection(grpcConfig *bean.ArgoGRPCConfig) *grpc.ClientConn { //TODO: acdAuthConfig should be passed as arg in function - acdAuthConfig := &bean.AcdAuthConfig{ - ClusterId: bean2.DefaultClusterId, - DevtronSecretName: impl.devtronSecretConfig.DevtronSecretName, - DevtronDexSecretNamespace: impl.devtronSecretConfig.DevtronDexSecretNamespace, - } - token, err := impl.GetLatestDevtronArgoCdUserToken(acdAuthConfig) + token, err := impl.getLatestDevtronArgoCdUserToken(grpcConfig) if err != nil { impl.logger.Errorw("error in getting latest devtron argocd user token", "err", err) } - return impl.getConnectionWithToken(token) + return impl.getConnectionWithToken(grpcConfig.ConnectionConfig, token) } -func (impl *ArgoCDConnectionManagerImpl) getConnectionWithToken(token string) *grpc.ClientConn { +func (impl *ArgoCDConnectionManagerImpl) getConnectionWithToken(connectionConfig *bean.Config, token string) *grpc.ClientConn { //TODO: config should be passed to this function as argument - conf, err := GetConfig() - if err != nil { - impl.logger.Errorw("error on get acd config while creating connection", "err", err) - return nil - } settings := impl.getArgoCdSettings() var option []grpc.DialOption option = append(option, grpc.WithTransportCredentials(GetTLS(settings.Certificate))) @@ -147,19 +147,19 @@ func (impl *ArgoCDConnectionManagerImpl) getConnectionWithToken(token string) *g option = append(option, grpc.WithPerRPCCredentials(TokenAuth{token: token})) } option = append(option, grpc.WithChainUnaryInterceptor(grpc_prometheus.UnaryClientInterceptor, otelgrpc.UnaryClientInterceptor()), grpc.WithChainStreamInterceptor(grpc_prometheus.StreamClientInterceptor, otelgrpc.StreamClientInterceptor())) - conn, err := grpc.Dial(fmt.Sprintf("%s:%s", conf.Host, conf.Port), option...) + conn, err := grpc.Dial(fmt.Sprintf("%s:%s", connectionConfig.Host, connectionConfig.Port), option...) if err != nil { return nil } return conn } -func (impl *ArgoCDConnectionManagerImpl) GetLatestDevtronArgoCdUserToken(authConfig *bean.AcdAuthConfig) (string, error) { - +func (impl *ArgoCDConnectionManagerImpl) getLatestDevtronArgoCdUserToken(grpcConfig *bean.ArgoGRPCConfig) (string, error) { var ( k8sClient *v1.CoreV1Client err error ) + authConfig := grpcConfig.AuthConfig if authConfig.ClusterId == bean2.DefaultClusterId { k8sClient, err = impl.k8sUtil.GetCoreV1ClientInCluster() if err != nil { @@ -200,7 +200,7 @@ func (impl *ArgoCDConnectionManagerImpl) GetLatestDevtronArgoCdUserToken(authCon if len(token) == 0 { newTokenNo := latestTokenNo + 1 - token, err = impl.createNewArgoCdTokenForDevtron(string(username), string(password), newTokenNo, k8sClient) + token, err = impl.createNewArgoCdTokenForDevtron(grpcConfig.ConnectionConfig, string(username), string(password), newTokenNo, k8sClient) if err != nil { impl.logger.Errorw("error in creating new argo cd token for devtron", "err", err) return "", err @@ -209,14 +209,7 @@ func (impl *ArgoCDConnectionManagerImpl) GetLatestDevtronArgoCdUserToken(authCon return token, nil } -func (impl *ArgoCDConnectionManagerImpl) GetOrUpdateArgoCdUserDetail() string { - - //TODO: authConfig should be passed as argument to this function - authConfig := &bean.AcdAuthConfig{ - ClusterId: bean2.DefaultClusterId, - DevtronSecretName: impl.devtronSecretConfig.DevtronSecretName, - DevtronDexSecretNamespace: impl.devtronSecretConfig.DevtronDexSecretNamespace, - } +func (impl *ArgoCDConnectionManagerImpl) GetOrUpdateArgoCdUserDetail(grpcConfig *bean.ArgoGRPCConfig) string { token := "" var ( @@ -224,6 +217,7 @@ func (impl *ArgoCDConnectionManagerImpl) GetOrUpdateArgoCdUserDetail() string { err error ) + authConfig := grpcConfig.AuthConfig if authConfig.ClusterId == bean2.DefaultClusterId { k8sClient, err = impl.k8sUtil.GetCoreV1ClientInCluster() if err != nil { @@ -262,7 +256,7 @@ func (impl *ArgoCDConnectionManagerImpl) GetOrUpdateArgoCdUserDetail() string { } } if !isTokenAvailable { - token, err = impl.createNewArgoCdTokenForDevtron(userNameStr, PasswordStr, 1, k8sClient) + token, err = impl.createNewArgoCdTokenForDevtron(grpcConfig.ConnectionConfig, userNameStr, PasswordStr, 1, k8sClient) if err != nil { impl.logger.Errorw("error in creating new argo cd token for devtron", "err", err) } @@ -293,9 +287,9 @@ func (impl *ArgoCDConnectionManagerImpl) createNewArgoCdUserForDevtron(k8sClient return username, password, nil } -func (impl *ArgoCDConnectionManagerImpl) createNewArgoCdTokenForDevtron(username, password string, tokenNo int, k8sClient *v1.CoreV1Client) (string, error) { +func (impl *ArgoCDConnectionManagerImpl) createNewArgoCdTokenForDevtron(connectionConfig *bean.Config, username, password string, tokenNo int, k8sClient *v1.CoreV1Client) (string, error) { //create new user at argo cd side - token, err := impl.createTokenForArgoCdUser(username, password) + token, err := impl.createTokenForArgoCdUser(connectionConfig, username, password) if err != nil { impl.logger.Errorw("error in creating new argocd user", "err", err) return "", err @@ -391,15 +385,15 @@ func (impl *ArgoCDConnectionManagerImpl) createNewArgoCdUser(username, password return nil } -func (impl *ArgoCDConnectionManagerImpl) createTokenForArgoCdUser(username, password string) (string, error) { - token, err := impl.passwordLogin(username, password) +func (impl *ArgoCDConnectionManagerImpl) createTokenForArgoCdUser(connectionConfig *bean.Config, username, password string) (string, error) { + token, err := impl.passwordLogin(connectionConfig, username, password) if err != nil { impl.logger.Errorw("error in getting jwt token with username & password", "err", err) return "", err } ctx := context.Background() ctx = context.WithValue(ctx, "token", token) - clientConn := impl.getConnectionWithToken(token) + clientConn := impl.getConnectionWithToken(connectionConfig, token) accountServiceClient := account.NewAccountServiceClient(clientConn) acdToken, err := accountServiceClient.CreateToken(ctx, &account.CreateTokenRequest{ Name: username, @@ -418,8 +412,8 @@ func (impl *ArgoCDConnectionManagerImpl) createTokenForArgoCdUser(username, pass return acdToken.Token, nil } -func (impl *ArgoCDConnectionManagerImpl) passwordLogin(username, password string) (string, error) { - conn := impl.getConnectionWithToken("") +func (impl *ArgoCDConnectionManagerImpl) passwordLogin(connectionConfig *bean.Config, username, password string) (string, error) { + conn := impl.getConnectionWithToken(connectionConfig, "") serviceClient := session.NewSessionServiceClient(conn) jwtToken, err := serviceClient.Create(context.Background(), username, password) return jwtToken, err @@ -471,7 +465,7 @@ func updateConfigMap(namespace string, cm *apiv1.ConfigMap, client *v1.CoreV1Cli } } -func SettingsManager(cfg *Config) (*settings.SettingsManager, error) { +func SettingsManager(cfg *bean.Config) (*settings.SettingsManager, error) { clientSet, kubeConfig := getK8sClient() namespace, _, err := kubeConfig.Namespace() if err != nil { diff --git a/client/argocdServer/helper.go b/client/argocdServer/helper.go new file mode 100644 index 0000000000..1d6eba751c --- /dev/null +++ b/client/argocdServer/helper.go @@ -0,0 +1,38 @@ +package argocdServer + +import ( + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func createRequestForArgoCDSyncModeUpdateRequest(argoApplication *v1alpha1.Application, autoSyncEnabled bool) *v1alpha1.Application { + // set automated field in update request + var automated *v1alpha1.SyncPolicyAutomated + if autoSyncEnabled { + automated = &v1alpha1.SyncPolicyAutomated{ + Prune: true, + } + } + return &v1alpha1.Application{ + ObjectMeta: v1.ObjectMeta{ + Name: argoApplication.Name, + Namespace: DevtronInstalationNs, + }, + Spec: v1alpha1.ApplicationSpec{ + Destination: argoApplication.Spec.Destination, + Source: argoApplication.Spec.Source, + SyncPolicy: &v1alpha1.SyncPolicy{ + Automated: automated, + SyncOptions: argoApplication.Spec.SyncPolicy.SyncOptions, + Retry: argoApplication.Spec.SyncPolicy.Retry, + }}} +} + +func isArgoAppSyncModeMigrationNeeded(argoApplication *v1alpha1.Application, acdConfig *ACDConfig) bool { + if acdConfig.IsManualSyncEnabled() && argoApplication.Spec.SyncPolicy.Automated != nil { + return true + } else if acdConfig.IsAutoSyncEnabled() && argoApplication.Spec.SyncPolicy.Automated == nil { + return true + } + return false +} diff --git a/client/argocdServer/repoCredsK8sClient/repositoryCredsManager.go b/client/argocdServer/repoCredsK8sClient/repoCreds.go similarity index 76% rename from client/argocdServer/repoCredsK8sClient/repositoryCredsManager.go rename to client/argocdServer/repoCredsK8sClient/repoCreds.go index 96e02f6ea1..ce08dda2e2 100644 --- a/client/argocdServer/repoCredsK8sClient/repositoryCredsManager.go +++ b/client/argocdServer/repoCredsK8sClient/repoCreds.go @@ -4,14 +4,14 @@ import ( "encoding/json" "fmt" "github.com/devtron-labs/common-lib/utils/k8s" + argoApplication "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient/bean" "github.com/devtron-labs/devtron/internal/sql/constants" - "github.com/devtron-labs/devtron/pkg/cluster" - util2 "github.com/devtron-labs/devtron/pkg/util" "github.com/ghodss/yaml" "github.com/google/uuid" "go.uber.org/zap" errors2 "k8s.io/apimachinery/pkg/api/errors" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" "net/http" url2 "net/url" "path" @@ -19,36 +19,39 @@ import ( "strings" ) -type RepositoryCreds interface { - AddOrUpdateOCIRegistry(username, password string, uniqueId int, registryUrl, repo string, isPublic bool) error - DeleteOCIRegistry(registryURL, repo string, ociRegistryId int) error - AddChartRepository(request bean.ChartRepositoryAddRequest) error - UpdateChartRepository(request bean.ChartRepositoryUpdateRequest) error - DeleteChartRepository(name, url string) error +type RepositoryCredsK8sClient interface { + AddOrUpdateOCIRegistry(argoK8sConfig *argoApplication.ArgoK8sConfig, username, password string, uniqueId int, registryUrl, repo string, isPublic bool) error + DeleteOCIRegistry(argoK8sConfig *argoApplication.ArgoK8sConfig, registryURL, repo string, ociRegistryId int) error + AddChartRepository(argoK8sConfig *argoApplication.ArgoK8sConfig, request bean.ChartRepositoryAddRequest) error + UpdateChartRepository(argoK8sConfig *argoApplication.ArgoK8sConfig, request bean.ChartRepositoryUpdateRequest) error + DeleteChartRepository(argoK8sConfig *argoApplication.ArgoK8sConfig, name, url string) error } -type RepositorySecretImpl struct { - logger *zap.SugaredLogger - K8sService k8s.K8sService - clusterService cluster.ClusterService - acdAuthConfig *util2.ACDAuthConfig +type RepositoryCredsK8sClientImpl struct { + logger *zap.SugaredLogger + K8sService k8s.K8sService } -func NewRepositorySecret( +func NewRepositoryCredsK8sClientImpl( logger *zap.SugaredLogger, K8sService k8s.K8sService, - clusterService cluster.ClusterService, - acdAuthConfig *util2.ACDAuthConfig, -) *RepositorySecretImpl { - return &RepositorySecretImpl{ - logger: logger, - K8sService: K8sService, - clusterService: clusterService, - acdAuthConfig: acdAuthConfig, +) *RepositoryCredsK8sClientImpl { + return &RepositoryCredsK8sClientImpl{ + logger: logger, + K8sService: K8sService, } } -func (impl *RepositorySecretImpl) AddOrUpdateOCIRegistry(username, password string, uniqueId int, registryUrl, repo string, isPublic bool) error { +func (impl *RepositoryCredsK8sClientImpl) getK8sClientByArgoK8sConfig(config *argoApplication.ArgoK8sConfig) (*v1.CoreV1Client, error) { + k8sClient, err := impl.K8sService.GetCoreV1ClientByRestConfig(config.RestConfig) + if err != nil { + impl.logger.Errorw("error in getting k8s client", "err", err) + return nil, err + } + return k8sClient, nil +} + +func (impl *RepositoryCredsK8sClientImpl) AddOrUpdateOCIRegistry(argoK8sConfig *argoApplication.ArgoK8sConfig, username, password string, uniqueId int, registryUrl, repo string, isPublic bool) error { secretData, uniqueSecretName, err := getSecretDataAndName( username, @@ -62,7 +65,7 @@ func (impl *RepositorySecretImpl) AddOrUpdateOCIRegistry(username, password stri return err } - err = impl.createOrUpdateArgoRepoSecret(uniqueSecretName, secretData) + err = impl.createOrUpdateArgoRepoSecret(argoK8sConfig, uniqueSecretName, secretData) if err != nil { impl.logger.Errorw("error in create/update k8s secret", "registryUrl", registryUrl, "repo", repo, "err", err) return err @@ -71,7 +74,7 @@ func (impl *RepositorySecretImpl) AddOrUpdateOCIRegistry(username, password stri } -func (impl *RepositorySecretImpl) DeleteOCIRegistry(registryURL, repo string, ociRegistryId int) error { +func (impl *RepositoryCredsK8sClientImpl) DeleteOCIRegistry(argoK8sConfig *argoApplication.ArgoK8sConfig, registryURL, repo string, ociRegistryId int) error { _, _, chartName, err := getHostAndFullRepoPathAndChartName(registryURL, repo) if err != nil { @@ -80,7 +83,7 @@ func (impl *RepositorySecretImpl) DeleteOCIRegistry(registryURL, repo string, oc uniqueSecretName := fmt.Sprintf("%s-%d", chartName, ociRegistryId) - err = impl.DeleteChartSecret(uniqueSecretName) + err = impl.DeleteChartSecret(argoK8sConfig, uniqueSecretName) if err != nil { impl.logger.Errorw("error in deleting oci registry secret", "secretName", uniqueSecretName, "err", err) return err @@ -88,29 +91,18 @@ func (impl *RepositorySecretImpl) DeleteOCIRegistry(registryURL, repo string, oc return nil } -func (impl *RepositorySecretImpl) createOrUpdateArgoRepoSecret(uniqueSecretName string, secretData map[string]string) error { - clusterBean, err := impl.clusterService.FindOne(cluster.DEFAULT_CLUSTER) - if err != nil { - impl.logger.Errorw("error in fetching cluster bean from db", "err", err) - return err - } - cfg := clusterBean.GetClusterConfig() - if err != nil { - impl.logger.Errorw("error in getting cluster config", "err", err) - return err - } - client, err := impl.K8sService.GetCoreV1Client(cfg) +func (impl *RepositoryCredsK8sClientImpl) createOrUpdateArgoRepoSecret(argoK8sConfig *argoApplication.ArgoK8sConfig, uniqueSecretName string, secretData map[string]string) error { + + k8sClient, err := impl.getK8sClientByArgoK8sConfig(argoK8sConfig) if err != nil { - impl.logger.Errorw("error in creating kubernetes client", "err", err) return err } secretLabel := make(map[string]string) secretLabel[bean.ARGOCD_REPOSITORY_SECRET_KEY] = bean.ARGOCD_REPOSITORY_SECRET_VALUE - err = impl.K8sService.CreateOrUpdateSecretByName( - client, - impl.acdAuthConfig.ACDConfigMapNamespace, + k8sClient, + argoK8sConfig.AcdNamespace, uniqueSecretName, secretLabel, secretData) @@ -177,16 +169,10 @@ func parseSecretDataForOCI(username, password, repoName, repoHost string, isPubl return secretData } -func (impl *RepositorySecretImpl) AddChartRepository(request bean.ChartRepositoryAddRequest) error { - clusterBean, err := impl.clusterService.FindOne(cluster.DEFAULT_CLUSTER) - if err != nil { - impl.logger.Errorw("error in fetching cluster bean from db", "err", err) - return err - } - cfg := clusterBean.GetClusterConfig() - client, err := impl.K8sService.GetCoreV1Client(cfg) +func (impl *RepositoryCredsK8sClientImpl) AddChartRepository(argoK8sConfig *argoApplication.ArgoK8sConfig, request bean.ChartRepositoryAddRequest) error { + + k8sClient, err := impl.getK8sClientByArgoK8sConfig(argoK8sConfig) if err != nil { - impl.logger.Errorw("error in creating kubernetes client", "err", err) return err } @@ -205,7 +191,7 @@ func (impl *RepositorySecretImpl) AddChartRepository(request bean.ChartRepositor request.URL, request.AllowInsecureConnection, request.IsPrivateChart) - _, err = impl.K8sService.CreateSecret(impl.acdAuthConfig.ACDConfigMapNamespace, nil, request.Name, "", client, secretLabel, secretData) + _, err = impl.K8sService.CreateSecret(argoK8sConfig.AcdNamespace, nil, request.Name, "", k8sClient, secretLabel, secretData) if err != nil { // TODO refactoring: Implement the below error handling if secret name already exists //if statusError, ok := err.(*k8sErrors.StatusError); ok && @@ -228,13 +214,9 @@ func (impl *RepositorySecretImpl) AddChartRepository(request bean.ChartRepositor return nil } -func (impl *RepositorySecretImpl) UpdateChartRepository(request bean.ChartRepositoryUpdateRequest) error { - clusterBean, err := impl.clusterService.FindOne(cluster.DEFAULT_CLUSTER) - if err != nil { - return err - } - cfg := clusterBean.GetClusterConfig() - client, err := impl.K8sService.GetCoreV1Client(cfg) +func (impl *RepositoryCredsK8sClientImpl) UpdateChartRepository(argoK8sConfig *argoApplication.ArgoK8sConfig, request bean.ChartRepositoryUpdateRequest) error { + + k8sClient, err := impl.getK8sClientByArgoK8sConfig(argoK8sConfig) if err != nil { return err } @@ -245,7 +227,7 @@ func (impl *RepositorySecretImpl) UpdateChartRepository(request bean.ChartReposi retryCount = retryCount + 1 var isFoundInArgoCdCm bool - cm, err := impl.K8sService.GetConfigMap(impl.acdAuthConfig.ACDConfigMapNamespace, impl.acdAuthConfig.ACDConfigMapName, client) + cm, err := impl.K8sService.GetConfigMap(argoK8sConfig.AcdNamespace, argoK8sConfig.AcdConfigMapName, k8sClient) if err != nil { return err } @@ -296,7 +278,7 @@ func (impl *RepositorySecretImpl) UpdateChartRepository(request bean.ChartReposi } } cm.Data = data - _, err = impl.K8sService.UpdateConfigMap(impl.acdAuthConfig.ACDConfigMapNamespace, cm, client) + _, err = impl.K8sService.UpdateConfigMap(argoK8sConfig.AcdNamespace, cm, k8sClient) } else { secretData := impl.CreateSecretDataForHelmChart(request.Name, request.Username, @@ -304,7 +286,7 @@ func (impl *RepositorySecretImpl) UpdateChartRepository(request bean.ChartReposi request.URL, request.AllowInsecureConnection, request.IsPrivateChart) - secret, err := impl.K8sService.GetSecret(impl.acdAuthConfig.ACDConfigMapNamespace, request.PreviousName, client) + secret, err := impl.K8sService.GetSecret(argoK8sConfig.AcdNamespace, request.PreviousName, k8sClient) statusError, ok := err.(*errors2.StatusError) if err != nil && (ok && statusError != nil && statusError.Status().Code != http.StatusNotFound) { impl.logger.Errorw("error in fetching secret", "err", err) @@ -314,7 +296,7 @@ func (impl *RepositorySecretImpl) UpdateChartRepository(request bean.ChartReposi if ok && statusError != nil && statusError.Status().Code == http.StatusNotFound { secretLabel := make(map[string]string) secretLabel[bean.ARGOCD_REPOSITORY_SECRET_KEY] = bean.ARGOCD_REPOSITORY_SECRET_VALUE - _, err = impl.K8sService.CreateSecret(impl.acdAuthConfig.ACDConfigMapNamespace, nil, request.PreviousName, "", client, secretLabel, secretData) + _, err = impl.K8sService.CreateSecret(argoK8sConfig.AcdNamespace, nil, request.PreviousName, "", k8sClient, secretLabel, secretData) if err != nil { impl.logger.Errorw("Error in creating secret for chart repo", "Chart Name", request.PreviousName, "err", err) continue @@ -324,20 +306,20 @@ func (impl *RepositorySecretImpl) UpdateChartRepository(request bean.ChartReposi } if request.PreviousName != request.Name { - err = impl.DeleteChartSecret(request.PreviousName) + err = impl.DeleteChartSecret(argoK8sConfig, request.PreviousName) if err != nil { impl.logger.Errorw("Error in deleting secret for chart repo", "Chart Name", request.Name, "err", err) continue } secretLabel := make(map[string]string) secretLabel[bean.ARGOCD_REPOSITORY_SECRET_KEY] = bean.ARGOCD_REPOSITORY_SECRET_VALUE - _, err = impl.K8sService.CreateSecret(impl.acdAuthConfig.ACDConfigMapNamespace, nil, request.Name, "", client, secretLabel, secretData) + _, err = impl.K8sService.CreateSecret(argoK8sConfig.AcdNamespace, nil, request.Name, "", k8sClient, secretLabel, secretData) if err != nil { impl.logger.Errorw("Error in creating secret for chart repo", "Chart Name", request.Name, "err", err) } } else { secret.StringData = secretData - _, err = impl.K8sService.UpdateSecret(impl.acdAuthConfig.ACDConfigMapNamespace, secret, client) + _, err = impl.K8sService.UpdateSecret(argoK8sConfig.AcdNamespace, secret, k8sClient) if err != nil { impl.logger.Errorw("Error in creating secret for chart repo", "Chart Name", request.Name, "err", err) } @@ -362,21 +344,16 @@ func (impl *RepositorySecretImpl) UpdateChartRepository(request bean.ChartReposi return nil } -func (impl *RepositorySecretImpl) DeleteChartSecret(secretName string) error { - clusterBean, err := impl.clusterService.FindOne(cluster.DEFAULT_CLUSTER) +func (impl *RepositoryCredsK8sClientImpl) DeleteChartSecret(argoK8sConfig *argoApplication.ArgoK8sConfig, secretName string) error { + k8sClient, err := impl.getK8sClientByArgoK8sConfig(argoK8sConfig) if err != nil { return err } - cfg := clusterBean.GetClusterConfig() - client, err := impl.K8sService.GetCoreV1Client(cfg) - if err != nil { - return err - } - err = impl.K8sService.DeleteSecret(impl.acdAuthConfig.ACDConfigMapNamespace, secretName, client) + err = impl.K8sService.DeleteSecret(argoK8sConfig.AcdNamespace, secretName, k8sClient) return err } -func (impl *RepositorySecretImpl) removeRepoData(data map[string]string, name string) (map[string]string, error) { +func (impl *RepositoryCredsK8sClientImpl) removeRepoData(data map[string]string, name string) (map[string]string, error) { helmRepoStr := data["helm.repositories"] helmRepoByte, err := yaml.YAMLToJSON([]byte(helmRepoStr)) if err != nil { @@ -455,7 +432,7 @@ func (impl *RepositorySecretImpl) removeRepoData(data map[string]string, name st } // updateRepoData update the request field in the argo-cm -func (impl *RepositorySecretImpl) updateRepoData(data map[string]string, name, authMode, username, password, sshKey, url string) (map[string]string, error) { +func (impl *RepositoryCredsK8sClientImpl) updateRepoData(data map[string]string, name, authMode, username, password, sshKey, url string) (map[string]string, error) { helmRepoStr := data["helm.repositories"] helmRepoByte, err := yaml.YAMLToJSON([]byte(helmRepoStr)) if err != nil { @@ -543,7 +520,7 @@ func (impl *RepositorySecretImpl) updateRepoData(data map[string]string, name, a return data, nil } -func (impl *RepositorySecretImpl) createRepoElement(authmode, username, password, sshKey, url, name string) *bean.AcdConfigMapRepositoriesDto { +func (impl *RepositoryCredsK8sClientImpl) createRepoElement(authmode, username, password, sshKey, url, name string) *bean.AcdConfigMapRepositoriesDto { repoData := &bean.AcdConfigMapRepositoriesDto{} if authmode == string(constants.AUTH_MODE_USERNAME_PASSWORD) { usernameSecret := &bean.KeyDto{Name: username, Key: "username"} @@ -564,7 +541,7 @@ func (impl *RepositorySecretImpl) createRepoElement(authmode, username, password } // Private helm charts credentials are saved as secrets -func (impl *RepositorySecretImpl) CreateSecretDataForHelmChart(name, username, password, repoURL string, allowInsecureConnection, isPrivateChart bool) (secretData map[string]string) { +func (impl *RepositoryCredsK8sClientImpl) CreateSecretDataForHelmChart(name, username, password, repoURL string, allowInsecureConnection, isPrivateChart bool) (secretData map[string]string) { secretData = make(map[string]string) secretData[bean.REPOSITORY_SECRET_NAME_KEY] = fmt.Sprintf("%s-%s", name, uuid.New().String()) // making repo name unique so that "helm repo add" command in argo-repo-server doesn't give error secretData[bean.REPOSITORY_SECRET_TYPE_KEY] = bean.REPOSITORY_TYPE_HELM @@ -581,17 +558,13 @@ func (impl *RepositorySecretImpl) CreateSecretDataForHelmChart(name, username, p return secretData } -func (impl *RepositorySecretImpl) DeleteChartRepository(name, url string) error { +func (impl *RepositoryCredsK8sClientImpl) DeleteChartRepository(argoK8sConfig *argoApplication.ArgoK8sConfig, name, url string) error { - clusterBean, err := impl.clusterService.FindOne(cluster.DEFAULT_CLUSTER) - if err != nil { - return err - } - cfg := clusterBean.GetClusterConfig() - client, err := impl.K8sService.GetCoreV1Client(cfg) + k8sClient, err := impl.getK8sClientByArgoK8sConfig(argoK8sConfig) if err != nil { return err } + updateSuccess := false retryCount := 0 //request.RedirectionUrl = "" @@ -600,7 +573,7 @@ func (impl *RepositorySecretImpl) DeleteChartRepository(name, url string) error retryCount = retryCount + 1 var isFoundInArgoCdCm bool - cm, err := impl.K8sService.GetConfigMap(impl.acdAuthConfig.ACDConfigMapNamespace, impl.acdAuthConfig.ACDConfigMapName, client) + cm, err := impl.K8sService.GetConfigMap(argoK8sConfig.AcdNamespace, argoK8sConfig.AcdConfigMapName, k8sClient) if err != nil { return err } @@ -637,9 +610,9 @@ func (impl *RepositorySecretImpl) DeleteChartRepository(name, url string) error } } cm.Data = data - _, err = impl.K8sService.UpdateConfigMap(impl.acdAuthConfig.ACDConfigMapNamespace, cm, client) + _, err = impl.K8sService.UpdateConfigMap(argoK8sConfig.AcdConfigMapName, cm, k8sClient) } else { - err = impl.DeleteChartSecret(name) + err = impl.DeleteChartSecret(argoK8sConfig, name) if err != nil { impl.logger.Errorw("Error in deleting secret for chart repo", "Chart Name", name, "err", err) } diff --git a/client/argocdServer/repocreds/repocreds.go b/client/argocdServer/repocreds/repocreds.go index ee5bb8573e..58d365ef8e 100644 --- a/client/argocdServer/repocreds/repocreds.go +++ b/client/argocdServer/repocreds/repocreds.go @@ -26,7 +26,7 @@ import ( ) type ServiceClient interface { - CreateRepoCreds(ctx context.Context, query *repocreds.RepoCredsCreateRequest) (*v1alpha1.RepoCreds, error) + CreateRepoCreds(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *repocreds.RepoCredsCreateRequest) (*v1alpha1.RepoCreds, error) } type ServiceClientImpl struct { @@ -41,16 +41,16 @@ func NewServiceClientImpl(logger *zap.SugaredLogger, argoCDConnectionManager con } } -func (r ServiceClientImpl) getService(ctx context.Context) (repocreds.RepoCredsServiceClient, error) { - conn := r.argoCDConnectionManager.GetConnection() +func (r ServiceClientImpl) getService(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig) (repocreds.RepoCredsServiceClient, error) { + conn := r.argoCDConnectionManager.GetGrpcClientConnection(grpcConfig) //defer conn.Close() return repocreds.NewRepoCredsServiceClient(conn), nil } -func (r ServiceClientImpl) CreateRepoCreds(ctx context.Context, query *repocreds.RepoCredsCreateRequest) (*v1alpha1.RepoCreds, error) { +func (r ServiceClientImpl) CreateRepoCreds(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *repocreds.RepoCredsCreateRequest) (*v1alpha1.RepoCreds, error) { ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutSlow) defer cancel() - client, err := r.getService(ctx) + client, err := r.getService(ctx, grpcConfig) if err != nil { return nil, err } diff --git a/client/argocdServer/repository/Repository.go b/client/argocdServer/repository/Repository.go index 3f56cc5b2e..05b8e0efb6 100644 --- a/client/argocdServer/repository/Repository.go +++ b/client/argocdServer/repository/Repository.go @@ -20,25 +20,13 @@ import ( "context" repository2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - "github.com/argoproj/argo-cd/v2/reposerver/apiclient" argoApplication "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/client/argocdServer/connection" "go.uber.org/zap" ) type ServiceClient interface { - // List returns list of repos - List(ctx context.Context, query *repository2.RepoQuery) (*v1alpha1.RepositoryList, error) - // ListApps returns list of apps in the repo - ListApps(ctx context.Context, query *repository2.RepoAppsQuery) (*repository2.RepoAppsResponse, error) - // GetAppDetails returns application details by given path - GetAppDetails(ctx context.Context, query *repository2.RepoAppDetailsQuery) (*apiclient.RepoAppDetailsResponse, error) - // Create creates a repo - Create(ctx context.Context, query *repository2.RepoCreateRequest) (*v1alpha1.Repository, error) - // Create creates a repo - Update(ctx context.Context, query *repository2.RepoUpdateRequest) (*v1alpha1.Repository, error) - // Delete deletes a repo - Delete(ctx context.Context, query *repository2.RepoQuery) (*repository2.RepoResponse, error) + Create(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *repository2.RepoCreateRequest) (*v1alpha1.Repository, error) } type ServiceClientImpl struct { @@ -53,69 +41,19 @@ func NewServiceClientImpl(logger *zap.SugaredLogger, argoCDConnectionManager con } } -func (r ServiceClientImpl) getService(ctx context.Context) (repository2.RepositoryServiceClient, error) { +func (r ServiceClientImpl) getService(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig) (repository2.RepositoryServiceClient, error) { - conn := r.argoCDConnectionManager.GetConnection() + conn := r.argoCDConnectionManager.GetGrpcClientConnection(grpcConfig) //defer conn.Close() return repository2.NewRepositoryServiceClient(conn), nil } -func (r ServiceClientImpl) List(ctx context.Context, query *repository2.RepoQuery) (*v1alpha1.RepositoryList, error) { - ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutFast) - defer cancel() - client, err := r.getService(ctx) - if err != nil { - return nil, err - } - return client.ListRepositories(ctx, query) -} - -func (r ServiceClientImpl) ListApps(ctx context.Context, query *repository2.RepoAppsQuery) (*repository2.RepoAppsResponse, error) { - ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutFast) - defer cancel() - client, err := r.getService(ctx) - if err != nil { - return nil, err - } - return client.ListApps(ctx, query) -} - -func (r ServiceClientImpl) GetAppDetails(ctx context.Context, query *repository2.RepoAppDetailsQuery) (*apiclient.RepoAppDetailsResponse, error) { - ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutFast) - defer cancel() - client, err := r.getService(ctx) - if err != nil { - return nil, err - } - return client.GetAppDetails(ctx, query) -} - -func (r ServiceClientImpl) Create(ctx context.Context, query *repository2.RepoCreateRequest) (*v1alpha1.Repository, error) { +func (r ServiceClientImpl) Create(ctx context.Context, grpcConfig *argoApplication.ArgoGRPCConfig, query *repository2.RepoCreateRequest) (*v1alpha1.Repository, error) { ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutSlow) defer cancel() - client, err := r.getService(ctx) + client, err := r.getService(ctx, grpcConfig) if err != nil { return nil, err } return client.CreateRepository(ctx, query) } - -func (r ServiceClientImpl) Update(ctx context.Context, query *repository2.RepoUpdateRequest) (*v1alpha1.Repository, error) { - ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutSlow) - defer cancel() - client, err := r.getService(ctx) - if err != nil { - return nil, err - } - return client.UpdateRepository(ctx, query) -} - -func (r ServiceClientImpl) Delete(ctx context.Context, query *repository2.RepoQuery) (*repository2.RepoResponse, error) { - ctx, cancel := context.WithTimeout(ctx, argoApplication.TimeoutSlow) - defer cancel() - client, err := r.getService(ctx) - if err != nil { - return nil, err - } - return client.DeleteRepository(ctx, query) -} diff --git a/cmd/external-app/wire.go b/cmd/external-app/wire.go index 44137bf475..c95eab1760 100644 --- a/cmd/external-app/wire.go +++ b/cmd/external-app/wire.go @@ -52,6 +52,9 @@ import ( "github.com/devtron-labs/devtron/api/team" "github.com/devtron-labs/devtron/api/terminal" webhookHelm "github.com/devtron-labs/devtron/api/webhook/helm" + "github.com/devtron-labs/devtron/client/argocdServer" + "github.com/devtron-labs/devtron/client/argocdServer/bean" + "github.com/devtron-labs/devtron/client/argocdServer/config" "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient" "github.com/devtron-labs/devtron/client/argocdServer/session" "github.com/devtron-labs/devtron/client/dashboard" @@ -77,8 +80,8 @@ import ( "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs" repository2 "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs/repository" "github.com/devtron-labs/devtron/pkg/pipeline" - "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning" - security2 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool" + security2 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/repository" "github.com/devtron-labs/devtron/pkg/sql" util2 "github.com/devtron-labs/devtron/pkg/util" util3 "github.com/devtron-labs/devtron/util" @@ -127,6 +130,7 @@ func InitializeApp() (*App, error) { telemetry.NewPosthogClient, delete2.NewDeleteServiceImpl, gitMaterial.GitMaterialWireSet, + scanTool.ScanToolWireSet, sql.NewTransactionUtilImpl, @@ -218,9 +222,6 @@ func InitializeApp() (*App, error) { kubernetesResourceAuditLogs.Newk8sResourceHistoryServiceImpl, wire.Bind(new(kubernetesResourceAuditLogs.K8sResourceHistoryService), new(*kubernetesResourceAuditLogs.K8sResourceHistoryServiceImpl)), - imageScanning.NewScanToolMetadataServiceImpl, - wire.Bind(new(imageScanning.ScanToolMetadataService), new(*imageScanning.ScanToolMetadataServiceImpl)), - security2.NewScanToolMetadataRepositoryImpl, wire.Bind(new(security2.ScanToolMetadataRepository), new(*security2.ScanToolMetadataRepositoryImpl)), @@ -255,8 +256,16 @@ func InitializeApp() (*App, error) { wire.Bind(new(util4.K8sService), new(*util4.K8sServiceImpl)), - repoCredsK8sClient.NewRepositorySecret, - wire.Bind(new(repoCredsK8sClient.RepositoryCreds), new(*repoCredsK8sClient.RepositorySecretImpl)), + repoCredsK8sClient.NewRepositoryCredsK8sClientImpl, + wire.Bind(new(repoCredsK8sClient.RepositoryCredsK8sClient), new(*repoCredsK8sClient.RepositoryCredsK8sClientImpl)), + + bean.GetConfig, + + config.NewArgoCDConfigGetter, + wire.Bind(new(config.ArgoCDConfigGetter), new(*config.ArgoCDConfigGetterImpl)), + + argocdServer.NewArgoClientWrapperServiceEAImpl, + wire.Bind(new(argocdServer.ArgoClientWrapperService), new(*argocdServer.ArgoClientWrapperServiceEAImpl)), dbMigration.NewDbMigrationServiceImpl, wire.Bind(new(dbMigration.DbMigration), new(*dbMigration.DbMigrationServiceImpl)), diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index 15b9eae6d0..b0fb03b956 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -46,6 +46,8 @@ import ( terminal2 "github.com/devtron-labs/devtron/api/terminal" webhookHelm2 "github.com/devtron-labs/devtron/api/webhook/helm" "github.com/devtron-labs/devtron/client/argocdServer" + "github.com/devtron-labs/devtron/client/argocdServer/bean" + "github.com/devtron-labs/devtron/client/argocdServer/config" "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient" "github.com/devtron-labs/devtron/client/dashboard" "github.com/devtron-labs/devtron/client/telemetry" @@ -73,7 +75,7 @@ import ( service4 "github.com/devtron-labs/devtron/pkg/appStore/values/service" "github.com/devtron-labs/devtron/pkg/argoApplication" read6 "github.com/devtron-labs/devtron/pkg/argoApplication/read" - config2 "github.com/devtron-labs/devtron/pkg/argoApplication/read/config" + config3 "github.com/devtron-labs/devtron/pkg/argoApplication/read/config" "github.com/devtron-labs/devtron/pkg/attributes" "github.com/devtron-labs/devtron/pkg/auth/authentication" "github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin" @@ -94,7 +96,7 @@ import ( "github.com/devtron-labs/devtron/pkg/clusterTerminalAccess" delete2 "github.com/devtron-labs/devtron/pkg/delete" "github.com/devtron-labs/devtron/pkg/deployment/common" - "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" + config2 "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/providerConfig" "github.com/devtron-labs/devtron/pkg/externalLink" "github.com/devtron-labs/devtron/pkg/fluxApplication" @@ -110,8 +112,8 @@ import ( "github.com/devtron-labs/devtron/pkg/module/repo" "github.com/devtron-labs/devtron/pkg/module/store" "github.com/devtron-labs/devtron/pkg/pipeline" - "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning" - repository11 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool" + repository11 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/repository" "github.com/devtron-labs/devtron/pkg/server" "github.com/devtron-labs/devtron/pkg/server/config" "github.com/devtron-labs/devtron/pkg/server/store" @@ -238,8 +240,14 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - repositorySecretImpl := repoCredsK8sClient.NewRepositorySecret(sugaredLogger, k8sServiceImpl, clusterServiceImpl, acdAuthConfig) - chartRepositoryServiceImpl := chartRepo.NewChartRepositoryServiceImpl(sugaredLogger, chartRepoRepositoryImpl, k8sServiceImpl, clusterServiceImpl, acdAuthConfig, httpClient, serverEnvConfigServerEnvConfig, repositorySecretImpl) + repositoryCredsK8sClientImpl := repoCredsK8sClient.NewRepositoryCredsK8sClientImpl(sugaredLogger, k8sServiceImpl) + beanConfig, err := bean.GetConfig() + if err != nil { + return nil, err + } + argoCDConfigGetterImpl := config.NewArgoCDConfigGetter(beanConfig, environmentVariables, acdAuthConfig, clusterReadServiceImpl, sugaredLogger, k8sServiceImpl) + argoClientWrapperServiceEAImpl := argocdServer.NewArgoClientWrapperServiceEAImpl(sugaredLogger, repositoryCredsK8sClientImpl, argoCDConfigGetterImpl) + chartRepositoryServiceImpl := chartRepo.NewChartRepositoryServiceImpl(sugaredLogger, chartRepoRepositoryImpl, k8sServiceImpl, acdAuthConfig, httpClient, serverEnvConfigServerEnvConfig, argoClientWrapperServiceEAImpl, clusterReadServiceImpl) installedAppRepositoryImpl := repository6.NewInstalledAppRepositoryImpl(sugaredLogger, db) helmClientConfig, err := gRPC.GetConfig() if err != nil { @@ -267,7 +275,7 @@ func InitializeApp() (*App, error) { dockerArtifactStoreRepositoryImpl := repository7.NewDockerArtifactStoreRepositoryImpl(db) dockerRegistryIpsConfigRepositoryImpl := repository7.NewDockerRegistryIpsConfigRepositoryImpl(db) ociRegistryConfigRepositoryImpl := repository7.NewOCIRegistryConfigRepositoryImpl(db) - dockerRegistryConfigImpl := pipeline.NewDockerRegistryConfigImpl(sugaredLogger, helmAppServiceImpl, dockerArtifactStoreRepositoryImpl, dockerRegistryIpsConfigRepositoryImpl, ociRegistryConfigRepositoryImpl, repositorySecretImpl) + dockerRegistryConfigImpl := pipeline.NewDockerRegistryConfigImpl(sugaredLogger, helmAppServiceImpl, dockerArtifactStoreRepositoryImpl, dockerRegistryIpsConfigRepositoryImpl, ociRegistryConfigRepositoryImpl, argoClientWrapperServiceEAImpl) deleteServiceImpl := delete2.NewDeleteServiceImpl(sugaredLogger, teamServiceImpl, clusterServiceImpl, environmentServiceImpl, chartRepositoryServiceImpl, installedAppRepositoryImpl, dockerRegistryConfigImpl, dockerArtifactStoreRepositoryImpl, k8sInformerFactoryImpl, k8sServiceImpl) teamRestHandlerImpl := team2.NewTeamRestHandlerImpl(sugaredLogger, teamServiceImpl, userServiceImpl, enforcerImpl, validate, userAuthServiceImpl, deleteServiceImpl) teamRouterImpl := team2.NewTeamRouterImpl(teamRestHandlerImpl) @@ -302,7 +310,7 @@ func InitializeApp() (*App, error) { deploymentConfigServiceImpl := common.NewDeploymentConfigServiceImpl(repositoryImpl, sugaredLogger, chartRepositoryImpl, pipelineRepositoryImpl, appRepositoryImpl, installedAppReadServiceEAImpl, environmentVariables) installedAppDBServiceImpl := EAMode.NewInstalledAppDBServiceImpl(sugaredLogger, installedAppRepositoryImpl, appRepositoryImpl, userServiceImpl, environmentServiceImpl, installedAppVersionHistoryRepositoryImpl, deploymentConfigServiceImpl) gitOpsConfigRepositoryImpl := repository5.NewGitOpsConfigRepositoryImpl(sugaredLogger, db) - gitOpsConfigReadServiceImpl := config.NewGitOpsConfigReadServiceImpl(sugaredLogger, gitOpsConfigRepositoryImpl, userServiceImpl, environmentVariables) + gitOpsConfigReadServiceImpl := config2.NewGitOpsConfigReadServiceImpl(sugaredLogger, gitOpsConfigRepositoryImpl, userServiceImpl, environmentVariables) attributesServiceImpl := attributes.NewAttributesServiceImpl(sugaredLogger, attributesRepositoryImpl) deploymentTypeOverrideServiceImpl := providerConfig.NewDeploymentTypeOverrideServiceImpl(sugaredLogger, environmentVariables, attributesServiceImpl) chartTemplateServiceImpl := util.NewChartTemplateServiceImpl(sugaredLogger) @@ -320,7 +328,7 @@ func InitializeApp() (*App, error) { fluxApplicationServiceImpl := fluxApplication.NewFluxApplicationServiceImpl(sugaredLogger, helmAppReadServiceImpl, clusterServiceImpl, helmAppClientImpl, pumpImpl) k8sResourceHistoryRepositoryImpl := repository10.NewK8sResourceHistoryRepositoryImpl(db, sugaredLogger) k8sResourceHistoryServiceImpl := kubernetesResourceAuditLogs.Newk8sResourceHistoryServiceImpl(k8sResourceHistoryRepositoryImpl, sugaredLogger, appRepositoryImpl, environmentRepositoryImpl) - argoApplicationConfigServiceImpl := config2.NewArgoApplicationConfigServiceImpl(sugaredLogger, k8sServiceImpl, clusterRepositoryImpl) + argoApplicationConfigServiceImpl := config3.NewArgoApplicationConfigServiceImpl(sugaredLogger, k8sServiceImpl, clusterRepositoryImpl) k8sCommonServiceImpl := k8s2.NewK8sCommonServiceImpl(sugaredLogger, k8sServiceImpl, argoApplicationConfigServiceImpl, clusterReadServiceImpl) ephemeralContainersRepositoryImpl := repository3.NewEphemeralContainersRepositoryImpl(db, transactionUtilImpl) ephemeralContainerServiceImpl := cluster.NewEphemeralContainerServiceImpl(ephemeralContainersRepositoryImpl, sugaredLogger) @@ -395,7 +403,7 @@ func InitializeApp() (*App, error) { return nil, err } scanToolMetadataRepositoryImpl := repository11.NewScanToolMetadataRepositoryImpl(db, sugaredLogger) - scanToolMetadataServiceImpl := imageScanning.NewScanToolMetadataServiceImpl(sugaredLogger, scanToolMetadataRepositoryImpl) + scanToolMetadataServiceImpl := scanTool.NewScanToolMetadataServiceImpl(sugaredLogger, scanToolMetadataRepositoryImpl) moduleServiceImpl := module.NewModuleServiceImpl(sugaredLogger, serverEnvConfigServerEnvConfig, moduleRepositoryImpl, moduleActionAuditLogRepositoryImpl, helmAppServiceImpl, serverDataStoreServerDataStore, serverCacheServiceImpl, moduleCacheServiceImpl, moduleCronServiceImpl, moduleServiceHelperImpl, moduleResourceStatusRepositoryImpl, scanToolMetadataServiceImpl) moduleRestHandlerImpl := module2.NewModuleRestHandlerImpl(sugaredLogger, moduleServiceImpl, userServiceImpl, enforcerImpl, validate) moduleRouterImpl := module2.NewModuleRouterImpl(moduleRestHandlerImpl) diff --git a/env_gen.json b/env_gen.json index fa7f25f157..3217f28913 100644 --- a/env_gen.json +++ b/env_gen.json @@ -1 +1 @@ -[{"Category":"CD","Fields":[{"Env":"ARGO_APP_MANUAL_SYNC_TIME","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_HELM_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_TIMEOUT_DURATION","EnvType":"string","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS","EnvType":"int","EnvValue":"12","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"6","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CD_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PIPELINE_DEGRADED_TIME","EnvType":"string","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_DEVTRON_APP","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_EXTERNAL_HELM_APP","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_HELM_APP","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"CI_RUNNER","Fields":[{"Env":"AZURE_ACCOUNT_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_ACCOUNT_NAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_CACHE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_LOG","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_CONNECTION_INSECURE","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_URL","EnvType":"string","EnvValue":"http://devtron-minio.devtroncd:9000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BASE_LOG_LOCATION_PATH","EnvType":"string","EnvValue":"/home/devtron/","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_GCP_CREDENTIALS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_PROVIDER","EnvType":"","EnvValue":"S3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ACCESS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_BUCKET_VERSIONED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT_INSECURE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_SECRET_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/devtron/buildx","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_K8S_DRIVER_OPTIONS","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_PROVENANCE_MODE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILD_LOG_TTL_VALUE_IN_SECS","EnvType":"int","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CACHE_LIMIT","EnvType":"int64","EnvValue":"5000000000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"cd-runner","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_IGNORE_DOCKER_CACHE","EnvType":"bool","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_RUNNER_DOCKER_MTU_VALUE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_SUCCESS_AUTO_TRIGGER_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_VOLUME_MOUNTS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"arsenal-v1/ci-artifacts","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_BUCKET","EnvType":"string","EnvValue":"devtron-pro-ci-logs","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"arsenal-v1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET","EnvType":"string","EnvValue":"ci-caching","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_LOGS_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_NAMESPACE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CI_IMAGE","EnvType":"string","EnvValue":"686244538589.dkr.ecr.us-east-2.amazonaws.com/cirunner:47","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtron-ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TARGET_PLATFORM","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DOCKER_BUILD_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/docker","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_BUILD_CONTEXT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_CM_NAME","EnvType":"string","EnvValue":"blob-storage-cm","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_SECRET_NAME","EnvType":"string","EnvValue":"blob-storage-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_API_SECRET","EnvType":"string","EnvValue":"devtroncd-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_PAYLOAD","EnvType":"string","EnvValue":"{\"ciProjectDetails\":[{\"gitRepository\":\"https://github.com/vikram1601/getting-started-nodejs.git\",\"checkoutPath\":\"./abc\",\"commitHash\":\"239077135f8cdeeccb7857e2851348f558cb53d3\",\"commitTime\":\"2022-10-30T20:00:00\",\"branch\":\"master\",\"message\":\"Update README.md\",\"author\":\"User Name \"}],\"dockerImage\":\"445808685819.dkr.ecr.us-east-2.amazonaws.com/orch:23907713-2\"}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_WEB_HOOK_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IGNORE_CM_CS_IN_CI_JOB","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_COUNT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_INTERVAL","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCANNER_ENDPOINT","EnvType":"string","EnvValue":"http://image-scanner-new-demo-devtroncd-service.devtroncd:80","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_MAX_RETRIES","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IN_APP_LOGGING_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_CD_WORKFLOW_RUNNER_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_CI_WORKFLOW_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODE","EnvType":"string","EnvValue":"DEV","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_SERVER_HOST","EnvType":"string","EnvValue":"localhost:4222","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_HOST","EnvType":"string","EnvValue":"http://devtroncd-orchestrator-service-prod.devtroncd/webhook/msg/nats","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PRE_CI_CACHE_PATH","EnvType":"string","EnvValue":"/devtroncd-cache","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOW_DOCKER_BUILD_ARGS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SKIP_CI_JOB_BUILD_CACHE_PUSH_PULL","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SKIP_CREATING_ECR_REPO","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINATION_GRACE_PERIOD_SECS","EnvType":"int","EnvValue":"180","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_QUERY_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CI_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BUILDX","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_DOCKER_API_TO_GET_DIGEST","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_EXTERNAL_NODE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WF_CONTROLLER_INSTANCE_ID","EnvType":"string","EnvValue":"devtron-runner","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_CACHE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"ci-runner","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"DEVTRON","Fields":[{"Env":"APP_SYNC_IMAGE","EnvType":"string","EnvValue":"quay.io/devtron/chart-sync:1227622d-132-3775","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_JOB_RESOURCES_OBJ","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_AUTO_SYNC_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_COUNT","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_DELAY","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ASYNC_BUILDX_CACHE_EXPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_MODE_MIN","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PORT","EnvType":"string","EnvValue":"8000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CExpirationTime","EnvType":"int","EnvValue":"600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_TRIGGER_CRON_TIME","EnvType":"int","EnvValue":"2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_STATUS_UPDATE_CRON","EnvType":"string","EnvValue":"*/5 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CLI_CMD_TIMEOUT_GLOBAL_SECONDS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CLUSTER_STATUS_CRON_TIME","EnvType":"int","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CONSUMER_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_LOG_TIME_LIMIT","EnvType":"int64","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_BOM_URL","EnvType":"string","EnvValue":"https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEX_SECRET_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_CHART_NAME","EnvType":"string","EnvValue":"devtron-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_URL","EnvType":"string","EnvValue":"https://helm.devtron.ai","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLATION_TYPE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_MODULES_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_SECRET_NAME","EnvType":"string","EnvValue":"devtron-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_VERSION_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.release","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CID","EnvType":"string","EnvValue":"example-app","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CLIENT_ID","EnvType":"string","EnvValue":"argo-cd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CSTOREKEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_JWTKEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_RURL","EnvType":"string","EnvValue":"http://127.0.0.1:8080/callback","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_SECRET","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ECR_REPO_NAME_PREFIX","EnvType":"string","EnvValue":"test/","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EPHEMERAL_SERVER_VERSION_REGEX","EnvType":"string","EnvValue":"v[1-9]\\.\\b(2[3-9]\\|[3-9][0-9])\\b.*","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EVENT_URL","EnvType":"string","EnvValue":"http://localhost:3000/notify","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXECUTE_WIRE_NIL_CHECKER","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CI_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FORCE_SECURITY_SCANNING","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_REPO_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_ORG_ID","EnvType":"int","EnvValue":"2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PASSWORD","EnvType":"string","EnvValue":"prom-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PORT","EnvType":"string","EnvValue":"8090","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HIDE_IMAGE_TAGGING_HARD_DELETE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IGNORE_AUTOCOMPLETE_AUTH_CHECK","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_GROUP_NAME","EnvType":"string","EnvValue":"installer.devtron.ai","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_RESOURCE","EnvType":"string","EnvValue":"installers","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_VERSION","EnvType":"string","EnvValue":"v1alpha1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IS_INTERNAL_USE","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"JwtExpirationTime","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_CLIENT_MAX_IDLE_CONNS_PER_HOST","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_IDLE_CONN_TIMEOUT","EnvType":"int","EnvValue":"300","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_KEEPALIVE","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_TIMEOUT","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TLS_HANDSHAKE_TIMEOUT","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_RECEIVE_MSG_SIZE","EnvType":"int","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_SEND_MSG_SIZE","EnvType":"int","EnvValue":"4","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_URL","EnvType":"string","EnvValue":"http://lens-milandevtron-service:80","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOGGER_DEV_MODE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_SESSION_PER_USER","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODULE_METADATA_API_URL","EnvType":"string","EnvValue":"https://api.devtron.ai/module?name=%s","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODULE_STATUS_HANDLING_CRON_DURATION_MIN","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_ACK_WAIT_IN_SECS","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_BUFFER_SIZE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_MAX_AGE","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_PROCESSING_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_REPLICAS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NOTIFICATION_MEDIUM","EnvType":"NotificationMedium","EnvValue":"rest","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"OTEL_COLLECTOR_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_EXPORT_PROM_METRICS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_FAILURE_QUERIES","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_QUERY","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_SLOW_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_QUERY_DUR_THRESHOLD","EnvType":"int64","EnvValue":"5000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PLUGIN_NAME","EnvType":"string","EnvValue":"Pull images from container repository","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROPAGATE_EXTRA_LABELS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROXY_SERVICE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESTRICT_TERMINAL_ACCESS_FOR_NON_SUPER_USER","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUNTIME_CONFIG_LOCAL_DEV","EnvType":"LocalDevMode","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_FORMAT","EnvType":"string","EnvValue":"@{{%s}}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_HANDLE_PRIMITIVES","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_NAME_REGEX","EnvType":"string","EnvValue":"^[a-zA-Z][a-zA-Z0-9_-]{0,62}[a-zA-Z0-9]$","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SOCKET_DISCONNECT_DELAY_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SOCKET_HEARTBEAT_SECONDS","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"STREAM_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SYSTEM_VAR_PREFIX","EnvType":"string","EnvValue":"DEVTRON_","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"default","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_INACTIVE_DURATION_IN_MINS","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_STATUS_SYNC_In_SECS","EnvType":"int","EnvValue":"600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_LOG_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PASSWORD","EnvType":"string","EnvValue":"postgrespw","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PORT","EnvType":"string","EnvValue":"55000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_FOR_FAILED_CI_BUILD","EnvType":"string","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_IN_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USER_SESSION_DURATION_SECONDS","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_API_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_CUSTOM_HTTP_TRANSPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_GIT_CLI","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_RBAC_CREATION_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"VARIABLE_CACHE_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"VARIABLE_EXPRESSION_REGEX","EnvType":"string","EnvValue":"@{{([^}]+)}}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WEBHOOK_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"GITOPS","Fields":[{"Env":"ACD_CM","EnvType":"string","EnvValue":"argocd-cm","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_PASSWORD","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_SECRET_NAME","EnvType":"string","EnvValue":"devtron-gitops-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS","EnvType":"string","EnvValue":"Deployment,Rollout,StatefulSet,ReplicaSet","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS_BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"INFRA_SETUP","Fields":[{"Env":"DASHBOARD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_PORT","EnvType":"string","EnvValue":"3000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_HOST","EnvType":"string","EnvValue":"http://localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_PORT","EnvType":"string","EnvValue":"5556","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_PROTOCOL","EnvType":"string","EnvValue":"REST","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_URL","EnvType":"string","EnvValue":"127.0.0.1:7070","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HELM_CLIENT_URL","EnvType":"string","EnvValue":"127.0.0.1:50051","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"POSTGRES","Fields":[{"Env":"APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"Application name","Example":"","Deprecated":"false"},{"Env":"CASBIN_DATABASE","EnvType":"string","EnvValue":"casbin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"address of postgres service","Example":"postgresql-postgresql.devtroncd","Deprecated":"false"},{"Env":"PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"postgres database to be made connection with","Example":"orchestrator, casbin, git_sensor, lens","Deprecated":"false"},{"Env":"PG_PASSWORD","EnvType":"string","EnvValue":"{password}","EnvDescription":"password for postgres, associated with PG_USER","Example":"confidential ;)","Deprecated":"false"},{"Env":"PG_PORT","EnvType":"string","EnvValue":"5432","EnvDescription":"port of postgresql service","Example":"5432","Deprecated":"false"},{"Env":"PG_READ_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"user for postgres","Example":"postgres","Deprecated":"false"},{"Env":"PG_WRITE_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"RBAC","Fields":[{"Env":"ENFORCER_CACHE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENFORCER_CACHE_EXPIRATION_IN_SEC","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENFORCER_MAX_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_CASBIN_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"}]}] \ No newline at end of file +[{"Category":"CD","Fields":[{"Env":"ARGO_APP_MANUAL_SYNC_TIME","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_HELM_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_TIMEOUT_DURATION","EnvType":"string","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS","EnvType":"int","EnvValue":"12","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"6","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CD_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PIPELINE_DEGRADED_TIME","EnvType":"string","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_DEVTRON_APP","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_EXTERNAL_HELM_APP","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_HELM_APP","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"CI_RUNNER","Fields":[{"Env":"AZURE_ACCOUNT_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_ACCOUNT_NAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_CACHE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_LOG","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_CONNECTION_INSECURE","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_URL","EnvType":"string","EnvValue":"http://devtron-minio.devtroncd:9000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BASE_LOG_LOCATION_PATH","EnvType":"string","EnvValue":"/home/devtron/","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_GCP_CREDENTIALS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_PROVIDER","EnvType":"","EnvValue":"S3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ACCESS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_BUCKET_VERSIONED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT_INSECURE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_SECRET_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/devtron/buildx","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_K8S_DRIVER_OPTIONS","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_PROVENANCE_MODE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILD_LOG_TTL_VALUE_IN_SECS","EnvType":"int","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CACHE_LIMIT","EnvType":"int64","EnvValue":"5000000000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"cd-runner","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_IGNORE_DOCKER_CACHE","EnvType":"bool","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_RUNNER_DOCKER_MTU_VALUE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_SUCCESS_AUTO_TRIGGER_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_VOLUME_MOUNTS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"arsenal-v1/ci-artifacts","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_BUCKET","EnvType":"string","EnvValue":"devtron-pro-ci-logs","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"arsenal-v1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET","EnvType":"string","EnvValue":"ci-caching","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_LOGS_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_NAMESPACE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CI_IMAGE","EnvType":"string","EnvValue":"686244538589.dkr.ecr.us-east-2.amazonaws.com/cirunner:47","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtron-ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TARGET_PLATFORM","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DOCKER_BUILD_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/docker","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_BUILD_CONTEXT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_CM_NAME","EnvType":"string","EnvValue":"blob-storage-cm","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_SECRET_NAME","EnvType":"string","EnvValue":"blob-storage-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_API_SECRET","EnvType":"string","EnvValue":"devtroncd-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_PAYLOAD","EnvType":"string","EnvValue":"{\"ciProjectDetails\":[{\"gitRepository\":\"https://github.com/vikram1601/getting-started-nodejs.git\",\"checkoutPath\":\"./abc\",\"commitHash\":\"239077135f8cdeeccb7857e2851348f558cb53d3\",\"commitTime\":\"2022-10-30T20:00:00\",\"branch\":\"master\",\"message\":\"Update README.md\",\"author\":\"User Name \"}],\"dockerImage\":\"445808685819.dkr.ecr.us-east-2.amazonaws.com/orch:23907713-2\"}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_WEB_HOOK_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IGNORE_CM_CS_IN_CI_JOB","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_COUNT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_INTERVAL","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCANNER_ENDPOINT","EnvType":"string","EnvValue":"http://image-scanner-new-demo-devtroncd-service.devtroncd:80","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_MAX_RETRIES","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IN_APP_LOGGING_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_CD_WORKFLOW_RUNNER_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_CI_WORKFLOW_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODE","EnvType":"string","EnvValue":"DEV","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_SERVER_HOST","EnvType":"string","EnvValue":"localhost:4222","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_HOST","EnvType":"string","EnvValue":"http://devtroncd-orchestrator-service-prod.devtroncd/webhook/msg/nats","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PRE_CI_CACHE_PATH","EnvType":"string","EnvValue":"/devtroncd-cache","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOW_DOCKER_BUILD_ARGS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SKIP_CI_JOB_BUILD_CACHE_PUSH_PULL","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SKIP_CREATING_ECR_REPO","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINATION_GRACE_PERIOD_SECS","EnvType":"int","EnvValue":"180","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_QUERY_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CI_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BUILDX","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_DOCKER_API_TO_GET_DIGEST","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_EXTERNAL_NODE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WF_CONTROLLER_INSTANCE_ID","EnvType":"string","EnvValue":"devtron-runner","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_CACHE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"ci-runner","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"DEVTRON","Fields":[{"Env":"-","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_IMAGE","EnvType":"string","EnvValue":"quay.io/devtron/chart-sync:1227622d-132-3775","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_JOB_RESOURCES_OBJ","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_AUTO_SYNC_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_COUNT","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_DELAY","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ASYNC_BUILDX_CACHE_EXPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_MODE_MIN","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PORT","EnvType":"string","EnvValue":"8000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CExpirationTime","EnvType":"int","EnvValue":"600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_TRIGGER_CRON_TIME","EnvType":"int","EnvValue":"2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_STATUS_UPDATE_CRON","EnvType":"string","EnvValue":"*/5 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CLI_CMD_TIMEOUT_GLOBAL_SECONDS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CLUSTER_STATUS_CRON_TIME","EnvType":"int","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CONSUMER_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_LOG_TIME_LIMIT","EnvType":"int64","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TIMEOUT","EnvType":"float64","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_BOM_URL","EnvType":"string","EnvValue":"https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEX_SECRET_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_CHART_NAME","EnvType":"string","EnvValue":"devtron-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_URL","EnvType":"string","EnvValue":"https://helm.devtron.ai","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLATION_TYPE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_MODULES_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_SECRET_NAME","EnvType":"string","EnvValue":"devtron-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_VERSION_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.release","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CID","EnvType":"string","EnvValue":"example-app","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CLIENT_ID","EnvType":"string","EnvValue":"argo-cd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CSTOREKEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_JWTKEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_RURL","EnvType":"string","EnvValue":"http://127.0.0.1:8080/callback","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_SECRET","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ECR_REPO_NAME_PREFIX","EnvType":"string","EnvValue":"test/","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EPHEMERAL_SERVER_VERSION_REGEX","EnvType":"string","EnvValue":"v[1-9]\\.\\b(2[3-9]\\|[3-9][0-9])\\b.*","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EVENT_URL","EnvType":"string","EnvValue":"http://localhost:3000/notify","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXECUTE_WIRE_NIL_CHECKER","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CI_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FORCE_SECURITY_SCANNING","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_REPO_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GO_RUNTIME_ENV","EnvType":"string","EnvValue":"production","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_ORG_ID","EnvType":"int","EnvValue":"2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PASSWORD","EnvType":"string","EnvValue":"prom-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PORT","EnvType":"string","EnvValue":"8090","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HIDE_IMAGE_TAGGING_HARD_DELETE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IGNORE_AUTOCOMPLETE_AUTH_CHECK","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_GROUP_NAME","EnvType":"string","EnvValue":"installer.devtron.ai","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_RESOURCE","EnvType":"string","EnvValue":"installers","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_VERSION","EnvType":"string","EnvValue":"v1alpha1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IS_INTERNAL_USE","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"JwtExpirationTime","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_CLIENT_MAX_IDLE_CONNS_PER_HOST","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_IDLE_CONN_TIMEOUT","EnvType":"int","EnvValue":"300","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_KEEPALIVE","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_TIMEOUT","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TLS_HANDSHAKE_TIMEOUT","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_RECEIVE_MSG_SIZE","EnvType":"int","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_SEND_MSG_SIZE","EnvType":"int","EnvValue":"4","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_URL","EnvType":"string","EnvValue":"http://lens-milandevtron-service:80","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOGGER_DEV_MODE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_SESSION_PER_USER","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODULE_METADATA_API_URL","EnvType":"string","EnvValue":"https://api.devtron.ai/module?name=%s","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODULE_STATUS_HANDLING_CRON_DURATION_MIN","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_ACK_WAIT_IN_SECS","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_BUFFER_SIZE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_MAX_AGE","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_PROCESSING_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_REPLICAS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NOTIFICATION_MEDIUM","EnvType":"NotificationMedium","EnvValue":"rest","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"OTEL_COLLECTOR_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_EXPORT_PROM_METRICS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_FAILURE_QUERIES","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_QUERY","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_SLOW_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_QUERY_DUR_THRESHOLD","EnvType":"int64","EnvValue":"5000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PLUGIN_NAME","EnvType":"string","EnvValue":"Pull images from container repository","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROPAGATE_EXTRA_LABELS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROXY_SERVICE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESTRICT_TERMINAL_ACCESS_FOR_NON_SUPER_USER","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUNTIME_CONFIG_LOCAL_DEV","EnvType":"LocalDevMode","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_FORMAT","EnvType":"string","EnvValue":"@{{%s}}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_HANDLE_PRIMITIVES","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_NAME_REGEX","EnvType":"string","EnvValue":"^[a-zA-Z][a-zA-Z0-9_-]{0,62}[a-zA-Z0-9]$","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOULD_CHECK_NAMESPACE_ON_CLONE","EnvType":"bool","EnvValue":"false","EnvDescription":"should we check if namespace exists or not while cloning app","Example":"","Deprecated":"false"},{"Env":"SOCKET_DISCONNECT_DELAY_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SOCKET_HEARTBEAT_SECONDS","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"STREAM_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SYSTEM_VAR_PREFIX","EnvType":"string","EnvValue":"DEVTRON_","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"default","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_INACTIVE_DURATION_IN_MINS","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_STATUS_SYNC_In_SECS","EnvType":"int","EnvValue":"600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_LOG_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PASSWORD","EnvType":"string","EnvValue":"postgrespw","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PORT","EnvType":"string","EnvValue":"55000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_FOR_FAILED_CI_BUILD","EnvType":"string","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_IN_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USER_SESSION_DURATION_SECONDS","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_API_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_CUSTOM_HTTP_TRANSPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_GIT_CLI","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_RBAC_CREATION_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"VARIABLE_CACHE_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"VARIABLE_EXPRESSION_REGEX","EnvType":"string","EnvValue":"@{{([^}]+)}}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WEBHOOK_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"GITOPS","Fields":[{"Env":"ACD_CM","EnvType":"string","EnvValue":"argocd-cm","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_PASSWORD","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_SECRET_NAME","EnvType":"string","EnvValue":"devtron-gitops-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS","EnvType":"string","EnvValue":"Deployment,Rollout,StatefulSet,ReplicaSet","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS_BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"INFRA_SETUP","Fields":[{"Env":"DASHBOARD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_PORT","EnvType":"string","EnvValue":"3000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_HOST","EnvType":"string","EnvValue":"http://localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_PORT","EnvType":"string","EnvValue":"5556","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_PROTOCOL","EnvType":"string","EnvValue":"REST","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_URL","EnvType":"string","EnvValue":"127.0.0.1:7070","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HELM_CLIENT_URL","EnvType":"string","EnvValue":"127.0.0.1:50051","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"POSTGRES","Fields":[{"Env":"APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"Application name","Example":"","Deprecated":"false"},{"Env":"CASBIN_DATABASE","EnvType":"string","EnvValue":"casbin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"address of postgres service","Example":"postgresql-postgresql.devtroncd","Deprecated":"false"},{"Env":"PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"postgres database to be made connection with","Example":"orchestrator, casbin, git_sensor, lens","Deprecated":"false"},{"Env":"PG_PASSWORD","EnvType":"string","EnvValue":"{password}","EnvDescription":"password for postgres, associated with PG_USER","Example":"confidential ;)","Deprecated":"false"},{"Env":"PG_PORT","EnvType":"string","EnvValue":"5432","EnvDescription":"port of postgresql service","Example":"5432","Deprecated":"false"},{"Env":"PG_READ_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"user for postgres","Example":"postgres","Deprecated":"false"},{"Env":"PG_WRITE_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"RBAC","Fields":[{"Env":"ENFORCER_CACHE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENFORCER_CACHE_EXPIRATION_IN_SEC","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENFORCER_MAX_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_CASBIN_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"}]}] \ No newline at end of file diff --git a/env_gen.md b/env_gen.md index e8d27af688..99d49b535d 100644 --- a/env_gen.md +++ b/env_gen.md @@ -117,6 +117,7 @@ ## DEVTRON Related Environment Variables | Key | Type | Default Value | Description | Example | Deprecated | |-------|----------|-------------------|-------------------|-----------------------|------------------| + | - | | | | | false | | APP_SYNC_IMAGE | string |quay.io/devtron/chart-sync:1227622d-132-3775 | | | false | | APP_SYNC_JOB_RESOURCES_OBJ | string | | | | false | | APP_SYNC_SERVICE_ACCOUNT | string |chart-sync | | | false | @@ -139,7 +140,7 @@ | CLUSTER_STATUS_CRON_TIME | int |15 | | | false | | CONSUMER_CONFIG_JSON | string | | | | false | | DEFAULT_LOG_TIME_LIMIT | int64 |1 | | | false | - | DEFAULT_TIMEOUT | int64 |3600 | | | false | + | DEFAULT_TIMEOUT | float64 |3600 | | | false | | DEVTRON_BOM_URL | string |https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml | | | false | | DEVTRON_DEFAULT_NAMESPACE | string |devtroncd | | | false | | DEVTRON_DEX_SECRET_NAMESPACE | string |devtroncd | | | false | @@ -170,6 +171,7 @@ | FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE | int |5 | | | false | | FORCE_SECURITY_SCANNING | bool |false | | | false | | GITOPS_REPO_PREFIX | string | | | | false | + | GO_RUNTIME_ENV | string |production | | | false | | GRAFANA_HOST | string |localhost | | | false | | GRAFANA_NAMESPACE | string |devtroncd | | | false | | GRAFANA_ORG_ID | int |2 | | | false | @@ -226,6 +228,7 @@ | SCOPED_VARIABLE_FORMAT | string |@{{%s}} | | | false | | SCOPED_VARIABLE_HANDLE_PRIMITIVES | bool |false | | | false | | SCOPED_VARIABLE_NAME_REGEX | string |^[a-zA-Z][a-zA-Z0-9_-]{0,62}[a-zA-Z0-9]$ | | | false | + | SHOULD_CHECK_NAMESPACE_ON_CLONE | bool |false | should we check if namespace exists or not while cloning app | | false | | SOCKET_DISCONNECT_DELAY_SECONDS | int |5 | | | false | | SOCKET_HEARTBEAT_SECONDS | int |25 | | | false | | STREAM_CONFIG_JSON | string | | | | false | diff --git a/go.mod b/go.mod index 3d8730fff3..86d9506f99 100644 --- a/go.mod +++ b/go.mod @@ -288,8 +288,8 @@ require gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect replace ( github.com/argoproj/argo-workflows/v3 v3.5.10 => github.com/devtron-labs/argo-workflows/v3 v3.5.13 - github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250116083207-90a2b2acbc2a - github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250122120743-f9dc0038c36a + github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2 + github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2 github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.5.5 k8s.io/api => k8s.io/api v0.29.7 diff --git a/go.sum b/go.sum index b2c283918a..50156b584f 100644 --- a/go.sum +++ b/go.sum @@ -792,10 +792,10 @@ github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzq github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/devtron-labs/argo-workflows/v3 v3.5.13 h1:3pINq0gXOSeTw2z/vYe+j80lRpSN5Rp/8mfQORh8SmU= github.com/devtron-labs/argo-workflows/v3 v3.5.13/go.mod h1:/vqxcovDPT4zqr4DjR5v7CF8ggpY1l3TSa2CIG3jmjA= -github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250116083207-90a2b2acbc2a h1:ianVrrotjgDSBLHiExJiqCzNq5WY7uvIvLZqzbuR+B8= -github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250116083207-90a2b2acbc2a/go.mod h1:5lv4Wfj5ERhhvDGXe2IeES6qxjvUVCcohaRwKnWBMNo= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250122120743-f9dc0038c36a h1:KKPEVBfa4sXptJc/0ZVWcxePI/JNtzQl0ugnwTePvgk= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250122120743-f9dc0038c36a/go.mod h1:1QJJLpgJSkb5Jm9xPeKAk+kXb0QgBOOOgJj0cgYhAVA= +github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2 h1:8QjRav7pCDb32Pz8HwbS1P8QQJ1QSDb3wJgAmNYkNeU= +github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2/go.mod h1:5lv4Wfj5ERhhvDGXe2IeES6qxjvUVCcohaRwKnWBMNo= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2 h1:8VByFEk14t2z2DDaD/7pTgwSM7zFYEMqfthLWpt2M3w= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2/go.mod h1:1QJJLpgJSkb5Jm9xPeKAk+kXb0QgBOOOgJj0cgYhAVA= github.com/devtron-labs/go-bitbucket v0.9.60-beta h1:VEx1jvDgdtDPS6A1uUFoaEi0l1/oLhbr+90xOwr6sDU= github.com/devtron-labs/go-bitbucket v0.9.60-beta/go.mod h1:GnuiCesvh8xyHeMCb+twm8lBR/kQzJYSKL28ZfObp1Y= github.com/devtron-labs/protos v0.0.3-0.20240802105333-92ee9bb85d80 h1:xwbTeijNTf4/j1v+tSfwVqwLVnReas/NqEKeQHvSTys= diff --git a/internal/sql/repository/CiArtifactRepository.go b/internal/sql/repository/CiArtifactRepository.go index f5767f33e8..2f3c41ae37 100644 --- a/internal/sql/repository/CiArtifactRepository.go +++ b/internal/sql/repository/CiArtifactRepository.go @@ -77,6 +77,7 @@ type CiArtifact struct { IsArtifactUploaded bool `sql:"is_artifact_uploaded"` // Deprecated; Use pipelineConfig.CiWorkflow instead. CredentialsSourceType string `sql:"credentials_source_type"` CredentialSourceValue string `sql:"credentials_source_value"` + TargetPlatforms string `sql:"target_platforms"` ComponentId int `sql:"component_id"` DeployedTime time.Time `sql:"-"` Deployed bool `sql:"-"` diff --git a/internal/sql/repository/pipelineConfig/CiWorkflowRepository.go b/internal/sql/repository/pipelineConfig/CiWorkflowRepository.go index 9593094a1f..f313bfe06b 100644 --- a/internal/sql/repository/pipelineConfig/CiWorkflowRepository.go +++ b/internal/sql/repository/pipelineConfig/CiWorkflowRepository.go @@ -120,6 +120,7 @@ type WorkflowWithArtifact struct { TriggeredBy int32 `sql:"triggered_by"` EmailId string `sql:"email_id"` Image string `sql:"image"` + TargetPlatforms string `sql:"target_platforms"` CiArtifactLocation string `sql:"ci_artifact_location"` CiArtifactId int `sql:"ci_artifact_id"` BlobStorageEnabled bool `sql:"blob_storage_enabled"` @@ -193,6 +194,7 @@ func (impl *CiWorkflowRepositoryImpl) FindByPipelineId(pipelineId int, offset in ColumnExpr("cia.id AS ci_artifact_id"). ColumnExpr("env.environment_name"). ColumnExpr("cia.image"). + ColumnExpr("cia.target_platforms"). ColumnExpr("cia.is_artifact_uploaded AS old_is_artifact_uploaded"). ColumnExpr("wf.*"). ColumnExpr("u.email_id"). diff --git a/internal/util/MergeUtil.go b/internal/util/MergeUtil.go index 6f1af6e8cc..357319bc36 100644 --- a/internal/util/MergeUtil.go +++ b/internal/util/MergeUtil.go @@ -19,7 +19,7 @@ package util import ( "encoding/json" "github.com/devtron-labs/devtron/api/bean" - "github.com/devtron-labs/devtron/util" + globalUtil "github.com/devtron-labs/devtron/util" jsonpatch "github.com/evanphx/json-patch" "go.uber.org/zap" "golang.org/x/exp/slices" @@ -122,7 +122,23 @@ func (m MergeUtil) ConfigMapMerge(appLevelConfigMapJson string, envLevelConfigMa return string(byteData), err } -func (m MergeUtil) ConfigSecretMerge(appLevelSecretJson string, envLevelSecretJson string, chartMajorVersion int, chartMinorVersion int, isJob bool) (data string, err error) { +func (m MergeUtil) ConfigSecretMergeForJob(appLevelSecretJson, envLevelSecretJson string) (data string, err error) { + return m.configSecretMerge(appLevelSecretJson, envLevelSecretJson, "", true) +} + +func (m MergeUtil) ConfigSecretMergeForCDStages(appLevelSecretJson, envLevelSecretJson, chartVersion string) (data string, err error) { + return m.configSecretMerge(appLevelSecretJson, envLevelSecretJson, chartVersion, false) +} + +func (m MergeUtil) configSecretMerge(appLevelSecretJson string, envLevelSecretJson string, chartVersion string, isJob bool) (data string, err error) { + var chartMajorVersion, chartMinorVersion int + if chartVersion != "" { + chartMajorVersion, chartMinorVersion, err = globalUtil.ExtractChartVersion(chartVersion) + if err != nil { + m.Logger.Errorw("chart version parsing", "err", err) + return "", err + } + } appLevelSecret := bean.ConfigSecretJson{} if appLevelSecretJson != "" { err = json.Unmarshal([]byte(appLevelSecretJson), &appLevelSecret) @@ -173,7 +189,7 @@ func mergeConfigMapsAndSecrets(envLevelCMCS []bean.ConfigSecretMap, appLevelSecr } func (m MergeUtil) processExternalSecrets(secret bean.ConfigSecretMap, chartMajorVersion int, chartMinorVersion int, isJob bool) bean.ConfigSecretMap { - if secret.ExternalType == util.AWSSecretsManager || secret.ExternalType == util.AWSSystemManager || secret.ExternalType == util.HashiCorpVault { + if secret.ExternalType == globalUtil.AWSSecretsManager || secret.ExternalType == globalUtil.AWSSystemManager || secret.ExternalType == globalUtil.HashiCorpVault { if secret.SecretData != nil && ((chartMajorVersion <= 3 && chartMinorVersion < 8) || isJob) { var es []map[string]interface{} esNew := make(map[string]interface{}) diff --git a/internal/util/ValidateUtil.go b/internal/util/ValidateUtil.go index 00339c051f..c5a40f73e4 100644 --- a/internal/util/ValidateUtil.go +++ b/internal/util/ValidateUtil.go @@ -95,6 +95,10 @@ func IntValidator() (*validator.Validate, error) { if err != nil { return v, err } + err = v.RegisterValidation("global-entity-name", validateGlobalEntityName) + if err != nil { + return v, err + } err = v.RegisterValidation("not-system-admin-user", validateForSystemOrAdminUser) if err != nil { return v, err @@ -129,3 +133,10 @@ func validateDockerImage(fl validator.FieldLevel) bool { } return false } + +func validateGlobalEntityName(fl validator.FieldLevel) bool { + // ^[a-z0-9]+(?:[-._]+[a-z0-9]+)*$ + hostnameRegexString := `^[a-z0-9]+(?:[-._]+[a-z0-9]+)*$` + hostnameRegexRFC952 := regexp.MustCompile(hostnameRegexString) + return hostnameRegexRFC952.MatchString(fl.Field().String()) +} diff --git a/pkg/app/AppListingService.go b/pkg/app/AppListingService.go index abd25e5d75..e9167aff94 100644 --- a/pkg/app/AppListingService.go +++ b/pkg/app/AppListingService.go @@ -43,7 +43,6 @@ import ( "time" "github.com/devtron-labs/devtron/api/bean" - application2 "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/internal/sql/models" "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/internal/sql/repository/chartConfig" @@ -130,7 +129,6 @@ func (req FetchAppListingRequest) GetNamespaceClusterMapping() (namespaceCluster type AppListingServiceImpl struct { Logger *zap.SugaredLogger - application application2.ServiceClient appRepository app.AppRepository appListingRepository repository.AppListingRepository appListingViewBuilder AppListingViewBuilder @@ -150,7 +148,7 @@ type AppListingServiceImpl struct { } func NewAppListingServiceImpl(Logger *zap.SugaredLogger, appListingRepository repository.AppListingRepository, - application application2.ServiceClient, appRepository app.AppRepository, + appRepository app.AppRepository, appListingViewBuilder AppListingViewBuilder, pipelineRepository pipelineConfig.PipelineRepository, linkoutsRepository repository.LinkoutsRepository, cdWorkflowRepository pipelineConfig.CdWorkflowRepository, pipelineOverrideRepository chartConfig.PipelineOverrideRepository, environmentRepository repository2.EnvironmentRepository, @@ -162,7 +160,6 @@ func NewAppListingServiceImpl(Logger *zap.SugaredLogger, appListingRepository re serviceImpl := &AppListingServiceImpl{ Logger: Logger, appListingRepository: appListingRepository, - application: application, appRepository: appRepository, appListingViewBuilder: appListingViewBuilder, pipelineRepository: pipelineRepository, diff --git a/pkg/app/AppService.go b/pkg/app/AppService.go index f590ab5d4d..541db8cc37 100644 --- a/pkg/app/AppService.go +++ b/pkg/app/AppService.go @@ -18,7 +18,6 @@ package app import ( "context" - "encoding/json" "errors" "fmt" health2 "github.com/argoproj/gitops-engine/pkg/health" @@ -52,7 +51,6 @@ import ( "github.com/devtron-labs/common-lib/utils/k8s/health" "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/client/argocdServer" - "github.com/devtron-labs/devtron/client/argocdServer/application" client "github.com/devtron-labs/devtron/client/events" "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/internal/sql/repository/app" @@ -64,7 +62,6 @@ import ( repository4 "github.com/devtron-labs/devtron/pkg/appStore/installedApp/repository" chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" "github.com/devtron-labs/devtron/pkg/commonService" - "github.com/devtron-labs/devtron/pkg/resourceQualifiers" "github.com/devtron-labs/devtron/pkg/sql" "github.com/devtron-labs/devtron/pkg/variables" _ "github.com/devtron-labs/devtron/pkg/variables/repository" @@ -106,7 +103,6 @@ type AppServiceImpl struct { pipelineRepository pipelineConfig.PipelineRepository eventClient client.EventClient eventFactory client.EventFactory - acdClient application.ServiceClient appRepository app.AppRepository configMapRepository chartConfig.ConfigMapRepository chartRepository chartRepoRepository.ChartRepository @@ -135,7 +131,6 @@ type AppService interface { UpdateReleaseStatus(request *bean.ReleaseStatusUpdateRequest) (bool, error) GetConfigMapAndSecretJson(appId int, envId int, pipelineId int) ([]byte, error) UpdateCdWorkflowRunnerByACDObject(app *v1alpha1.Application, cdWfrId int, updateTimedOutStatus bool) error - GetCmSecretNew(appId int, envId int, isJob bool, scope resourceQualifiers.Scope) (*bean.ConfigMapJson, *bean.ConfigSecretJson, error) UpdateDeploymentStatusForGitOpsPipelines(app *v1alpha1.Application, statusTime time.Time, isAppStore bool) (bool, bool, *chartConfig.PipelineOverride, error) WriteCDSuccessEvent(appId int, envId int, override *chartConfig.PipelineOverride) CreateGitOpsRepo(app *app.App, userId int32) (gitopsRepoName string, chartGitAttr *commonBean.ChartGitAttribute, err error) @@ -151,7 +146,7 @@ func NewAppService( mergeUtil *MergeUtil, logger *zap.SugaredLogger, pipelineRepository pipelineConfig.PipelineRepository, eventClient client.EventClient, eventFactory client.EventFactory, - acdClient application.ServiceClient, appRepository app.AppRepository, + appRepository app.AppRepository, configMapRepository chartConfig.ConfigMapRepository, chartRepository chartRepoRepository.ChartRepository, cdWorkflowRepository pipelineConfig.CdWorkflowRepository, @@ -177,7 +172,6 @@ func NewAppService( pipelineRepository: pipelineRepository, eventClient: eventClient, eventFactory: eventFactory, - acdClient: acdClient, appRepository: appRepository, configMapRepository: configMapRepository, chartRepository: chartRepository, @@ -845,81 +839,6 @@ func (impl *AppServiceImpl) CreateGitOpsRepo(app *app.App, userId int32) (gitops return gitOpsRepoName, chartGitAttr, nil } -// FIXME tmp workaround -func (impl *AppServiceImpl) GetCmSecretNew(appId int, envId int, isJob bool, scope resourceQualifiers.Scope) (*bean.ConfigMapJson, *bean.ConfigSecretJson, error) { - var configMapJson string - var secretDataJson string - var configMapJsonApp string - var secretDataJsonApp string - var configMapJsonEnv string - var secretDataJsonEnv string - // var configMapJsonPipeline string - // var secretDataJsonPipeline string - - configMapA, err := impl.configMapRepository.GetByAppIdAppLevel(appId) - if err != nil && pg.ErrNoRows != err { - return nil, nil, err - } - if configMapA != nil && configMapA.Id > 0 { - configMapJsonApp = configMapA.ConfigMapData - secretDataJsonApp = configMapA.SecretData - } - - configMapE, err := impl.configMapRepository.GetByAppIdAndEnvIdEnvLevel(appId, envId) - if err != nil && pg.ErrNoRows != err { - return nil, nil, err - } - if configMapE != nil && configMapE.Id > 0 { - configMapJsonEnv = configMapE.ConfigMapData - secretDataJsonEnv = configMapE.SecretData - } - - configMapJson, err = impl.mergeUtil.ConfigMapMerge(configMapJsonApp, configMapJsonEnv) - if err != nil { - return nil, nil, err - } - var chartMajorVersion int - var chartMinorVersion int - if !isJob { - chart, err := impl.commonService.FetchLatestChart(appId, envId) - if err != nil { - return nil, nil, err - } - - chartVersion := chart.ChartVersion - chartMajorVersion, chartMinorVersion, err = util2.ExtractChartVersion(chartVersion) - if err != nil { - impl.logger.Errorw("chart version parsing", "err", err) - return nil, nil, err - } - } - secretDataJson, err = impl.mergeUtil.ConfigSecretMerge(secretDataJsonApp, secretDataJsonEnv, chartMajorVersion, chartMinorVersion, isJob) - if err != nil { - return nil, nil, err - } - configResponse := bean.ConfigMapJson{} - if configMapJson != "" { - err = json.Unmarshal([]byte(configMapJson), &configResponse) - if err != nil { - return nil, nil, err - } - } - secretResponse := bean.ConfigSecretJson{} - if configMapJson != "" { - err = json.Unmarshal([]byte(secretDataJson), &secretResponse) - if err != nil { - return nil, nil, err - } - } - - resolvedConfigResponse, resolvedSecretResponse, err := impl.scopedVariableManager.ResolveForPrePostStageTrigger(scope, configResponse, secretResponse, configMapA.Id, configMapE.Id) - if err != nil { - return nil, nil, err - } - - return resolvedConfigResponse, resolvedSecretResponse, nil -} - // depricated // TODO remove this method func (impl *AppServiceImpl) GetConfigMapAndSecretJson(appId int, envId int, pipelineId int) ([]byte, error) { diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/FullModeDeploymentService.go b/pkg/appStore/installedApp/service/FullMode/deployment/FullModeDeploymentService.go index e7eb3c012a..4f54e81799 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/FullModeDeploymentService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/FullModeDeploymentService.go @@ -23,7 +23,6 @@ import ( "fmt" "github.com/devtron-labs/devtron/api/helm-app/gRPC" client "github.com/devtron-labs/devtron/api/helm-app/service" - "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/timelineStatus" "github.com/devtron-labs/devtron/pkg/appStore/installedApp/service/common" repository5 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" @@ -37,7 +36,6 @@ import ( openapi "github.com/devtron-labs/devtron/api/helm-app/openapiClient" "github.com/devtron-labs/devtron/client/argocdServer" - application2 "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/app/status" @@ -76,7 +74,6 @@ type FullModeDeploymentService interface { type FullModeDeploymentServiceImpl struct { Logger *zap.SugaredLogger - acdClient application2.ServiceClient argoK8sClient argocdServer.ArgoK8sClient aCDAuthConfig *util2.ACDAuthConfig chartGroupDeploymentRepository repository2.ChartGroupDeploymentRepository @@ -97,12 +94,10 @@ type FullModeDeploymentServiceImpl struct { environmentRepository repository5.EnvironmentRepository deploymentConfigService common.DeploymentConfigService chartTemplateService util.ChartTemplateService - RepositorySecretService repoCredsK8sClient.RepositoryCreds } func NewFullModeDeploymentServiceImpl( logger *zap.SugaredLogger, - acdClient application2.ServiceClient, argoK8sClient argocdServer.ArgoK8sClient, aCDAuthConfig *util2.ACDAuthConfig, chartGroupDeploymentRepository repository2.ChartGroupDeploymentRepository, @@ -122,11 +117,9 @@ func NewFullModeDeploymentServiceImpl( gitOpsValidationService validation.GitOpsValidationService, environmentRepository repository5.EnvironmentRepository, deploymentConfigService common.DeploymentConfigService, - chartTemplateService util.ChartTemplateService, - RepositorySecretService repoCredsK8sClient.RepositoryCreds) *FullModeDeploymentServiceImpl { + chartTemplateService util.ChartTemplateService) *FullModeDeploymentServiceImpl { return &FullModeDeploymentServiceImpl{ Logger: logger, - acdClient: acdClient, argoK8sClient: argoK8sClient, aCDAuthConfig: aCDAuthConfig, chartGroupDeploymentRepository: chartGroupDeploymentRepository, @@ -147,7 +140,6 @@ func NewFullModeDeploymentServiceImpl( environmentRepository: environmentRepository, deploymentConfigService: deploymentConfigService, chartTemplateService: chartTemplateService, - RepositorySecretService: RepositorySecretService, } } diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppArgoCdService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppArgoCdService.go index d2b30dcab3..5f2a1d6bfc 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppArgoCdService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppArgoCdService.go @@ -18,11 +18,10 @@ package deployment import ( "context" - "encoding/json" "fmt" - "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/devtron-labs/devtron/client/argocdServer" + argoApplication "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/timelineStatus" "github.com/devtron-labs/devtron/internal/util" appStoreBean "github.com/devtron-labs/devtron/pkg/appStore/bean" @@ -53,7 +52,7 @@ type InstalledAppArgoCdService interface { func (impl *FullModeDeploymentServiceImpl) GetAcdAppGitOpsRepoName(appName string, environmentName string) (string, error) { //this method should only call in case of argo-integration and gitops configured acdAppName := util2.BuildDeployedAppName(appName, environmentName) - return impl.argoClientWrapperService.GetGitOpsRepoName(context.Background(), acdAppName) + return impl.argoClientWrapperService.GetGitOpsRepoNameForApplication(context.Background(), acdAppName) } func (impl *FullModeDeploymentServiceImpl) DeleteACDAppObject(ctx context.Context, appName string, environmentName string, installAppVersionRequest *appStoreBean.InstallAppVersionDTO) error { @@ -84,7 +83,7 @@ func (impl *FullModeDeploymentServiceImpl) DeleteACDAppObject(ctx context.Contex } func (impl *FullModeDeploymentServiceImpl) CheckIfArgoAppExists(acdAppName string) (isFound bool, err error) { - _, acdAppGetErr := impl.acdClient.Get(context.Background(), &application.ApplicationQuery{Name: &acdAppName}) + _, acdAppGetErr := impl.argoClientWrapperService.GetArgoAppByName(context.Background(), acdAppName) isFound = acdAppGetErr == nil return isFound, nil } @@ -98,7 +97,7 @@ func isArgoCdGitOpsRepoUrlOutOfSync(argoApplication *v1alpha1.Application, gitOp func (impl *FullModeDeploymentServiceImpl) UpdateAndSyncACDApps(installAppVersionRequest *appStoreBean.InstallAppVersionDTO, ChartGitAttribute *commonBean.ChartGitAttribute, isMonoRepoMigrationRequired bool, ctx context.Context, tx *pg.Tx) error { acdAppName := installAppVersionRequest.ACDAppName - argoApplication, err := impl.acdClient.Get(ctx, &application.ApplicationQuery{Name: &acdAppName}) + argoApplication, err := impl.argoClientWrapperService.GetArgoAppByName(ctx, acdAppName) if err != nil { impl.Logger.Errorw("Service err:UpdateAndSyncACDApps - error in acd app by name", "acdAppName", acdAppName, "err", err) return err @@ -152,15 +151,12 @@ func (impl *FullModeDeploymentServiceImpl) UpgradeDeployment(installAppVersionRe } func (impl *FullModeDeploymentServiceImpl) DeleteACD(acdAppName string, ctx context.Context, isNonCascade bool) error { - req := new(application.ApplicationDeleteRequest) - req.Name = &acdAppName cascadeDelete := !isNonCascade - req.Cascade = &cascadeDelete if ctx == nil { impl.Logger.Errorw("err in delete ACD for AppStore, ctx is NULL", "acdAppName", acdAppName) return fmt.Errorf("context is null") } - if _, err := impl.acdClient.Delete(ctx, req); err != nil { + if _, err := impl.argoClientWrapperService.DeleteArgoApp(ctx, acdAppName, cascadeDelete); err != nil { impl.Logger.Errorw("err in delete ACD for AppStore", "acdAppName", acdAppName, "err", err) return err } @@ -202,16 +198,17 @@ func (impl *FullModeDeploymentServiceImpl) patchAcdApp(ctx context.Context, inst return err } // update acd app - patchReq := v1alpha1.Application{Spec: v1alpha1.ApplicationSpec{Source: &v1alpha1.ApplicationSource{Path: chartGitAttr.ChartLocation, RepoURL: chartGitAttr.RepoUrl, TargetRevision: "master"}}} - reqbyte, err := json.Marshal(patchReq) - if err != nil { - impl.Logger.Errorw("error in creating patch", "err", err) - } - reqString := string(reqbyte) - patchType := "merge" - _, err = impl.acdClient.Patch(ctx, &application.ApplicationPatchRequest{Patch: &reqString, Name: &installAppVersionRequest.ACDAppName, PatchType: &patchType}) + + patchReq := &argoApplication.ArgoCdAppPatchReqDto{ + ArgoAppName: installAppVersionRequest.ACDAppName, + ChartLocation: chartGitAttr.ChartLocation, + GitRepoUrl: chartGitAttr.RepoUrl, + TargetRevision: "master", + PatchType: "merge", + } + err = impl.argoClientWrapperService.PatchArgoCdApp(ctx, patchReq) if err != nil { - impl.Logger.Errorw("error in creating argo app ", "name", installAppVersionRequest.ACDAppName, "patch", string(reqbyte), "err", err) + impl.Logger.Errorw("error in patching acd app ", "appName", installAppVersionRequest.ACDAppName, "err", err) return err } return nil @@ -220,5 +217,5 @@ func (impl *FullModeDeploymentServiceImpl) patchAcdApp(ctx context.Context, inst func (impl *FullModeDeploymentServiceImpl) GetAcdAppGitOpsRepoURL(appName string, environmentName string) (string, error) { ctx := context.Background() acdAppName := util2.BuildDeployedAppName(appName, environmentName) - return impl.argoClientWrapperService.GetGitOpsRepoURL(ctx, acdAppName) + return impl.argoClientWrapperService.GetGitOpsRepoURLForApplication(ctx, acdAppName) } diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index 0943420954..f960a44760 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -406,7 +406,7 @@ func (impl *FullModeDeploymentServiceImpl) CreateArgoRepoSecretIfNeeded(appStore appStore := appStoreApplicationVersion.AppStore dockerArtifactStore := appStoreApplicationVersion.AppStore.DockerArtifactStore - err = impl.RepositorySecretService.AddOrUpdateOCIRegistry( + err = impl.argoClientWrapperService.AddOrUpdateOCIRegistry( dockerArtifactStore.Username, dockerArtifactStore.Password, dockerArtifactStore.OCIRegistryConfig[0].Id, diff --git a/pkg/appStore/installedApp/service/FullMode/deploymentTypeChange/InstalledAppDeploymentTypeChangeService.go b/pkg/appStore/installedApp/service/FullMode/deploymentTypeChange/InstalledAppDeploymentTypeChangeService.go index d9abc1ce24..7e2eed87af 100644 --- a/pkg/appStore/installedApp/service/FullMode/deploymentTypeChange/InstalledAppDeploymentTypeChangeService.go +++ b/pkg/appStore/installedApp/service/FullMode/deploymentTypeChange/InstalledAppDeploymentTypeChangeService.go @@ -27,7 +27,6 @@ import ( client "github.com/devtron-labs/devtron/api/helm-app/service" helmBean "github.com/devtron-labs/devtron/api/helm-app/service/bean" "github.com/devtron-labs/devtron/client/argocdServer" - application2 "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/internal/constants" appRepository "github.com/devtron-labs/devtron/internal/sql/repository/app" appStatus2 "github.com/devtron-labs/devtron/internal/sql/repository/appStatus" @@ -73,7 +72,6 @@ type InstalledAppDeploymentTypeChangeServiceImpl struct { appRepository appRepository.AppRepository gitOpsConfigReadService config.GitOpsConfigReadService environmentRepository repository.EnvironmentRepository - acdClient application2.ServiceClient k8sCommonService k8s.K8sCommonService k8sUtil k8s2.K8sService fullModeDeploymentService deployment.FullModeDeploymentService @@ -93,7 +91,7 @@ func NewInstalledAppDeploymentTypeChangeServiceImpl(logger *zap.SugaredLogger, appStatusRepository appStatus2.AppStatusRepository, gitOpsConfigReadService config.GitOpsConfigReadService, environmentRepository repository.EnvironmentRepository, - acdClient application2.ServiceClient, k8sCommonService k8s.K8sCommonService, + k8sCommonService k8s.K8sCommonService, k8sUtil k8s2.K8sService, fullModeDeploymentService deployment.FullModeDeploymentService, eaModeDeploymentService deployment2.EAModeDeploymentService, argoClientWrapperService argocdServer.ArgoClientWrapperService, @@ -110,7 +108,6 @@ func NewInstalledAppDeploymentTypeChangeServiceImpl(logger *zap.SugaredLogger, appStatusRepository: appStatusRepository, gitOpsConfigReadService: gitOpsConfigReadService, environmentRepository: environmentRepository, - acdClient: acdClient, k8sCommonService: k8sCommonService, k8sUtil: k8sUtil, fullModeDeploymentService: fullModeDeploymentService, @@ -629,10 +626,7 @@ func (impl *InstalledAppDeploymentTypeChangeServiceImpl) fetchDeletedInstalledAp } _, err = impl.helmAppService.GetApplicationDetail(ctx, appIdentifier) } else { - req := &application.ApplicationQuery{ - Name: &deploymentAppName, - } - _, err = impl.acdClient.Get(ctx, req) + _, err = impl.argoClientWrapperService.GetArgoAppByName(ctx, deploymentAppName) } if err != nil { impl.logger.Errorw("error in getting application detail", "deploymentAppName", deploymentAppName, "err", err) diff --git a/pkg/appStore/installedApp/service/FullMode/resource/ResourceTreeService.go b/pkg/appStore/installedApp/service/FullMode/resource/ResourceTreeService.go index a2bad6fab6..f6bccf4ba6 100644 --- a/pkg/appStore/installedApp/service/FullMode/resource/ResourceTreeService.go +++ b/pkg/appStore/installedApp/service/FullMode/resource/ResourceTreeService.go @@ -29,7 +29,7 @@ import ( "github.com/devtron-labs/devtron/api/helm-app/service" "github.com/devtron-labs/devtron/api/helm-app/service/bean" "github.com/devtron-labs/devtron/api/helm-app/service/read" - application2 "github.com/devtron-labs/devtron/client/argocdServer/application" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/internal/constants" repository2 "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry" "github.com/devtron-labs/devtron/internal/util" @@ -64,7 +64,7 @@ type InstalledAppResourceServiceImpl struct { logger *zap.SugaredLogger installedAppRepository repository.InstalledAppRepository appStoreApplicationVersionRepository appStoreDiscoverRepository.AppStoreApplicationVersionRepository - acdClient application2.ServiceClient + acdClientWrapper argocdServer.ArgoClientWrapperService aCDAuthConfig *util3.ACDAuthConfig installedAppRepositoryHistory repository.InstalledAppVersionHistoryRepository helmAppService service.HelmAppService @@ -81,7 +81,7 @@ type InstalledAppResourceServiceImpl struct { func NewInstalledAppResourceServiceImpl(logger *zap.SugaredLogger, installedAppRepository repository.InstalledAppRepository, appStoreApplicationVersionRepository appStoreDiscoverRepository.AppStoreApplicationVersionRepository, - acdClient application2.ServiceClient, + acdClientWrapper argocdServer.ArgoClientWrapperService, aCDAuthConfig *util3.ACDAuthConfig, installedAppRepositoryHistory repository.InstalledAppVersionHistoryRepository, helmAppService service.HelmAppService, @@ -95,7 +95,7 @@ func NewInstalledAppResourceServiceImpl(logger *zap.SugaredLogger, logger: logger, installedAppRepository: installedAppRepository, appStoreApplicationVersionRepository: appStoreApplicationVersionRepository, - acdClient: acdClient, + acdClientWrapper: acdClientWrapper, aCDAuthConfig: aCDAuthConfig, installedAppRepositoryHistory: installedAppRepositoryHistory, helmAppService: helmAppService, @@ -362,7 +362,7 @@ func (impl *InstalledAppResourceServiceImpl) checkForHibernation(ctx context.Con canBeHibernated := false alreadyHibernated := false ctx, _ = context.WithTimeout(ctx, 60*time.Second) - res, err := impl.acdClient.GetResource(ctx, rQuery) + res, err := impl.acdClientWrapper.GetApplicationResource(ctx, rQuery) if err != nil { impl.logger.Errorw("error getting response from acdClient", "request", rQuery, "data", res, "timeTaken", time.Since(t0), "err", err) return canBeHibernated, alreadyHibernated diff --git a/pkg/argoApplication/ArgoApplicationServiceExtended.go b/pkg/argoApplication/ArgoApplicationServiceExtended.go index d94b4ee36a..fe2ca85067 100644 --- a/pkg/argoApplication/ArgoApplicationServiceExtended.go +++ b/pkg/argoApplication/ArgoApplicationServiceExtended.go @@ -10,7 +10,7 @@ import ( "github.com/devtron-labs/devtron/api/helm-app/gRPC" openapi "github.com/devtron-labs/devtron/api/helm-app/openapiClient" "github.com/devtron-labs/devtron/api/helm-app/service" - application3 "github.com/devtron-labs/devtron/client/argocdServer/application" + "github.com/devtron-labs/devtron/client/argocdServer" argoApplication "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/pkg/argoApplication/bean" "github.com/devtron-labs/devtron/pkg/argoApplication/read/config" @@ -25,7 +25,7 @@ import ( type ArgoApplicationServiceExtendedImpl struct { *ArgoApplicationServiceImpl - acdClient application3.ServiceClient + acdClientWrapper argocdServer.ArgoClientWrapperService } func NewArgoApplicationServiceExtendedServiceImpl(logger *zap.SugaredLogger, @@ -34,7 +34,8 @@ func NewArgoApplicationServiceExtendedServiceImpl(logger *zap.SugaredLogger, helmAppClient gRPC.HelmAppClient, helmAppService service.HelmAppService, k8sApplicationService application.K8sApplicationService, - argoApplicationConfigService config.ArgoApplicationConfigService, acdClient application3.ServiceClient) *ArgoApplicationServiceExtendedImpl { + argoApplicationConfigService config.ArgoApplicationConfigService, + acdClientWrapper argocdServer.ArgoClientWrapperService) *ArgoApplicationServiceExtendedImpl { return &ArgoApplicationServiceExtendedImpl{ ArgoApplicationServiceImpl: &ArgoApplicationServiceImpl{ logger: logger, @@ -45,7 +46,7 @@ func NewArgoApplicationServiceExtendedServiceImpl(logger *zap.SugaredLogger, k8sApplicationService: k8sApplicationService, argoApplicationConfigService: argoApplicationConfigService, }, - acdClient: acdClient, + acdClientWrapper: acdClientWrapper, } } @@ -64,7 +65,7 @@ func (impl *ArgoApplicationServiceExtendedImpl) ResourceTree(ctxt context.Contex ctx, cancel := context.WithTimeout(ctxt, argoApplication.TimeoutSlow) defer cancel() - asc, conn, err := impl.acdClient.GetArgoClient(ctxt) + asc, conn, err := impl.acdClientWrapper.GetArgoClient(ctxt) if err != nil { impl.logger.Errorw("Error in GetArgoClient", "err", err) return nil, err diff --git a/pkg/bean/app.go b/pkg/bean/app.go index 74c5db98dd..b4dd9f7f22 100644 --- a/pkg/bean/app.go +++ b/pkg/bean/app.go @@ -18,6 +18,7 @@ package bean import ( "encoding/json" + bean4 "github.com/devtron-labs/common-lib/utils/bean" bean2 "github.com/devtron-labs/devtron/api/bean/AppView" "github.com/devtron-labs/devtron/internal/sql/constants" repository3 "github.com/devtron-labs/devtron/internal/sql/repository" @@ -827,6 +828,7 @@ type CiArtifactBean struct { CiWorkflowId int `json:"-"` RegistryType string `json:"registryType"` RegistryName string `json:"registryName"` + TargetPlatforms []*bean4.TargetPlatform `json:"targetPlatforms"` CiPipelineId int `json:"-"` CredentialsSourceType string `json:"-"` CredentialsSourceValue string `json:"-"` diff --git a/pkg/chartRepo/ChartRepositoryService.go b/pkg/chartRepo/ChartRepositoryService.go index 43078ea2bc..deaa4f1127 100644 --- a/pkg/chartRepo/ChartRepositoryService.go +++ b/pkg/chartRepo/ChartRepositoryService.go @@ -21,8 +21,10 @@ import ( "errors" "fmt" util3 "github.com/devtron-labs/common-lib/utils/k8s" - "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient/bean" + bean2 "github.com/devtron-labs/devtron/pkg/cluster/bean" + "github.com/devtron-labs/devtron/pkg/cluster/read" "io" "io/ioutil" "net/http" @@ -33,7 +35,6 @@ import ( "github.com/devtron-labs/devtron/internal/util" chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" - "github.com/devtron-labs/devtron/pkg/cluster" serverEnvConfig "github.com/devtron-labs/devtron/pkg/server/config" "github.com/devtron-labs/devtron/pkg/sql" util2 "github.com/devtron-labs/devtron/pkg/util" @@ -76,28 +77,29 @@ type ChartRepositoryService interface { } type ChartRepositoryServiceImpl struct { - logger *zap.SugaredLogger - repoRepository chartRepoRepository.ChartRepoRepository - K8sUtil *util3.K8sServiceImpl - clusterService cluster.ClusterService - aCDAuthConfig *util2.ACDAuthConfig - client *http.Client - serverEnvConfig *serverEnvConfig.ServerEnvConfig - RepositoryCredsManager repoCredsK8sClient.RepositoryCreds + logger *zap.SugaredLogger + repoRepository chartRepoRepository.ChartRepoRepository + K8sUtil *util3.K8sServiceImpl + aCDAuthConfig *util2.ACDAuthConfig + client *http.Client + serverEnvConfig *serverEnvConfig.ServerEnvConfig + argoClientWrapperService argocdServer.ArgoClientWrapperService + clusterReadService read.ClusterReadService } -func NewChartRepositoryServiceImpl(logger *zap.SugaredLogger, repoRepository chartRepoRepository.ChartRepoRepository, K8sUtil *util3.K8sServiceImpl, clusterService cluster.ClusterService, +func NewChartRepositoryServiceImpl(logger *zap.SugaredLogger, repoRepository chartRepoRepository.ChartRepoRepository, K8sUtil *util3.K8sServiceImpl, aCDAuthConfig *util2.ACDAuthConfig, client *http.Client, serverEnvConfig *serverEnvConfig.ServerEnvConfig, - RepositoryCredsManager repoCredsK8sClient.RepositoryCreds) *ChartRepositoryServiceImpl { + argoClientWrapperService argocdServer.ArgoClientWrapperService, + clusterReadService read.ClusterReadService) *ChartRepositoryServiceImpl { return &ChartRepositoryServiceImpl{ - logger: logger, - repoRepository: repoRepository, - K8sUtil: K8sUtil, - clusterService: clusterService, - aCDAuthConfig: aCDAuthConfig, - client: client, - serverEnvConfig: serverEnvConfig, - RepositoryCredsManager: RepositoryCredsManager, + logger: logger, + repoRepository: repoRepository, + K8sUtil: K8sUtil, + aCDAuthConfig: aCDAuthConfig, + client: client, + serverEnvConfig: serverEnvConfig, + argoClientWrapperService: argoClientWrapperService, + clusterReadService: clusterReadService, } } @@ -160,7 +162,7 @@ func (impl *ChartRepositoryServiceImpl) CreateChartRepo(request *ChartRepoDto) ( IsPrivateChart: isPrivateChart, } - err = impl.RepositoryCredsManager.AddChartRepository(argoServerAddRequest) + err = impl.argoClientWrapperService.AddChartRepository(argoServerAddRequest) if err != nil { impl.logger.Errorw("error in adding chart repository to argocd server", "name", request.Name, "err", err) return nil, err @@ -247,7 +249,7 @@ func (impl *ChartRepositoryServiceImpl) UpdateData(request *ChartRepoDto) (*char IsPrivateChart: isPrivateChart, } // modify configmap - err = impl.RepositoryCredsManager.UpdateChartRepository(argoServerUpdateRequest) + err = impl.argoClientWrapperService.UpdateChartRepository(argoServerUpdateRequest) if err != nil { return nil, err } @@ -292,7 +294,7 @@ func (impl *ChartRepositoryServiceImpl) DeleteChartRepo(request *ChartRepoDto) e } // modify configmap - err = impl.RepositoryCredsManager.DeleteChartRepository(request.Name, request.Url) + err = impl.argoClientWrapperService.DeleteChartRepository(request.Name, request.Url) if err != nil { impl.logger.Errorw("error in deleting chart repository from argocd", "name", request.Name, "err", err) return err @@ -499,7 +501,7 @@ func (impl *ChartRepositoryServiceImpl) ValidateAndUpdateChartRepo(request *Char } func (impl *ChartRepositoryServiceImpl) TriggerChartSyncManual(chartProviderConfig *ChartProviderConfig) error { - defaultClusterBean, err := impl.clusterService.FindOne(cluster.DEFAULT_CLUSTER) + defaultClusterBean, err := impl.clusterReadService.FindOne(bean2.DEFAULT_CLUSTER) if err != nil { impl.logger.Errorw("defaultClusterBean err, TriggerChartSyncManual", "err", err) return err diff --git a/pkg/cluster/ClusterService.go b/pkg/cluster/ClusterService.go index 72359a54d1..9bab50066a 100644 --- a/pkg/cluster/ClusterService.go +++ b/pkg/cluster/ClusterService.go @@ -49,6 +49,7 @@ import ( bean2 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/util" + clusterBean "github.com/devtron-labs/devtron/pkg/cluster/bean" "github.com/devtron-labs/devtron/pkg/cluster/repository" globalUtil "github.com/devtron-labs/devtron/util" "github.com/go-pg/pg" @@ -414,7 +415,7 @@ func (impl *ClusterServiceImpl) Update(ctx context.Context, bean *bean.ClusterBe } if bean.ServerUrl != model.ServerUrl || bean.InsecureSkipTLSVerify != model.InsecureSkipTlsVerify || dbConfigBearerToken != requestConfigBearerToken || dbConfigTlsKey != requestConfigTlsKey || dbConfigCertData != requestConfigCertData || dbConfigCAData != requestConfigCAData { - if bean.ClusterName == DEFAULT_CLUSTER { + if bean.ClusterName == clusterBean.DEFAULT_CLUSTER { impl.logger.Errorw("default_cluster is reserved by the system and cannot be updated, default_cluster", "name", bean.ClusterName) return nil, fmt.Errorf("default_cluster is reserved by the system and cannot be updated") } @@ -908,7 +909,7 @@ func (impl *ClusterServiceImpl) ValidateKubeconfig(kubeConfig string) (map[strin clusterBeanObject.ErrorInConnecting = "cluster name missing from kubeconfig" } - if clusterBeanObject.ClusterName == DEFAULT_CLUSTER { + if clusterBeanObject.ClusterName == clusterBean.DEFAULT_CLUSTER { clusterBeanObject.ErrorInConnecting = "default_cluster is reserved by the system and cannot be updated" } diff --git a/pkg/cluster/ClusterServiceExtended.go b/pkg/cluster/ClusterServiceExtended.go index 1b0362d311..f8876cb66f 100644 --- a/pkg/cluster/ClusterServiceExtended.go +++ b/pkg/cluster/ClusterServiceExtended.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "github.com/devtron-labs/common-lib/utils/k8s/commonBean" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/pkg/cluster/bean" "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" @@ -29,7 +30,6 @@ import ( cluster3 "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - cluster2 "github.com/devtron-labs/devtron/client/argocdServer/cluster" "github.com/devtron-labs/devtron/client/grafana" "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/util" @@ -42,21 +42,21 @@ type ClusterServiceImplExtended struct { environmentRepository repository.EnvironmentRepository grafanaClient grafana.GrafanaClient installedAppRepository repository2.InstalledAppRepository - clusterServiceCD cluster2.ServiceClient + argoCDClientWrapper argocdServer.ArgoClientWrapperService gitOpsConfigReadService config.GitOpsConfigReadService *ClusterServiceImpl } func NewClusterServiceImplExtended(environmentRepository repository.EnvironmentRepository, grafanaClient grafana.GrafanaClient, installedAppRepository repository2.InstalledAppRepository, - clusterServiceCD cluster2.ServiceClient, gitOpsConfigReadService config.GitOpsConfigReadService, - clusterServiceImpl *ClusterServiceImpl) *ClusterServiceImplExtended { + clusterServiceImpl *ClusterServiceImpl, + argoCDClientWrapper argocdServer.ArgoClientWrapperService) *ClusterServiceImplExtended { clusterServiceExt := &ClusterServiceImplExtended{ environmentRepository: environmentRepository, grafanaClient: grafanaClient, installedAppRepository: installedAppRepository, - clusterServiceCD: clusterServiceCD, + argoCDClientWrapper: argoCDClientWrapper, gitOpsConfigReadService: gitOpsConfigReadService, ClusterServiceImpl: clusterServiceImpl, } @@ -265,7 +265,7 @@ func (impl *ClusterServiceImplExtended) Update(ctx context.Context, bean *bean.C Config: cdClusterConfig, } - _, err = impl.clusterServiceCD.Update(ctx, &cluster3.ClusterUpdateRequest{Cluster: cl}) + _, err = impl.argoCDClientWrapper.UpdateCluster(ctx, &cluster3.ClusterUpdateRequest{Cluster: cl}) if err != nil { impl.logger.Errorw("service err, Update", "error", err, "payload", cl) @@ -354,7 +354,7 @@ func (impl *ClusterServiceImplExtended) Save(ctx context.Context, bean *bean.Clu //create it into argo cd as well cl := impl.ConvertClusterBeanObjectToCluster(bean) - _, err = impl.clusterServiceCD.Create(ctx, &cluster3.ClusterCreateRequest{Upsert: true, Cluster: cl}) + _, err = impl.argoCDClientWrapper.CreateCluster(ctx, &cluster3.ClusterCreateRequest{Upsert: true, Cluster: cl}) if err != nil { impl.logger.Errorw("service err, Save", "err", err, "payload", cl) err1 := impl.ClusterServiceImpl.Delete(bean, userId) //FIXME nishant call local diff --git a/pkg/cluster/bean/bean.go b/pkg/cluster/bean/bean.go index 3ff44f887b..6548613adb 100644 --- a/pkg/cluster/bean/bean.go +++ b/pkg/cluster/bean/bean.go @@ -7,6 +7,7 @@ import ( const ( DefaultClusterId = 1 + DEFAULT_CLUSTER = "default_cluster" ) type PrometheusAuth struct { diff --git a/pkg/cluster/read/ClusterReadService.go b/pkg/cluster/read/ClusterReadService.go index 10b278bdd6..e2619151a3 100644 --- a/pkg/cluster/read/ClusterReadService.go +++ b/pkg/cluster/read/ClusterReadService.go @@ -10,6 +10,7 @@ import ( type ClusterReadService interface { IsClusterReachable(clusterId int) (bool, error) FindById(id int) (*bean.ClusterBean, error) + FindOne(clusterName string) (*bean.ClusterBean, error) } type ClusterReadServiceImpl struct { @@ -46,3 +47,12 @@ func (impl *ClusterReadServiceImpl) FindById(id int) (*bean.ClusterBean, error) bean := adapter.GetClusterBean(*model) return &bean, nil } + +func (impl *ClusterReadServiceImpl) FindOne(clusterName string) (*bean.ClusterBean, error) { + model, err := impl.clusterRepository.FindOne(clusterName) + if err != nil { + return nil, err + } + bean := adapter.GetClusterBean(*model) + return &bean, nil +} diff --git a/pkg/commonService/CommonService.go b/pkg/commonService/CommonService.go index bd5c7bf795..267b4c445d 100644 --- a/pkg/commonService/CommonService.go +++ b/pkg/commonService/CommonService.go @@ -34,7 +34,7 @@ import ( ) type CommonService interface { - FetchLatestChart(appId int, envId int) (*chartRepoRepository.Chart, error) + FetchLatestChartVersion(appId int, envId int) (string, error) GlobalChecklist() (*GlobalChecklist, error) } @@ -102,18 +102,18 @@ type AppChecklist struct { //ChartChecklist *ChartChecklist `json:",inline"` } -func (impl *CommonServiceImpl) FetchLatestChart(appId int, envId int) (*chartRepoRepository.Chart, error) { +func (impl *CommonServiceImpl) FetchLatestChartVersion(appId int, envId int) (string, error) { var chart *chartRepoRepository.Chart if appId > 0 && envId > 0 { envOverride, err := impl.envConfigOverrideReadService.ActiveEnvConfigOverride(appId, envId) if err != nil { - return nil, err + return "", err } //if chart is overrides in env, and not mark as overrides in db, it means it was not completed and refer to latest to the app. if (envOverride.Id == 0) || (envOverride.Id > 0 && !envOverride.IsOverride) { chart, err = impl.chartRepository.FindLatestChartForAppByAppId(appId) if err != nil { - return nil, err + return "", err } } else { //if chart is overrides in env, it means it may have different version than app level. @@ -122,14 +122,17 @@ func (impl *CommonServiceImpl) FetchLatestChart(appId int, envId int) (*chartRep } else if appId > 0 { chartG, err := impl.chartRepository.FindLatestChartForAppByAppId(appId) if err != nil { - return nil, err + return "", err } chart = chartG //TODO - note if secret create/update from global with property (new style). // there may be older chart version in env overrides (and in that case it will be ignore, property and isBinary) } - return chart, nil + if chart == nil { + return "", nil + } + return chart.ChartVersion, nil } func (impl *CommonServiceImpl) GlobalChecklist() (*GlobalChecklist, error) { diff --git a/pkg/commonService/mocks/CommonService.go b/pkg/commonService/mocks/CommonService.go index 9ae240cc30..814ae91e24 100644 --- a/pkg/commonService/mocks/CommonService.go +++ b/pkg/commonService/mocks/CommonService.go @@ -1,11 +1,9 @@ -// Code generated by mockery v2.20.0. DO NOT EDIT. +// Code generated by mockery v2.42.0. DO NOT EDIT. package mocks import ( - chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" commonService "github.com/devtron-labs/devtron/pkg/commonService" - mock "github.com/stretchr/testify/mock" ) @@ -14,21 +12,23 @@ type CommonService struct { mock.Mock } -// FetchLatestChart provides a mock function with given fields: appId, envId -func (_m *CommonService) FetchLatestChart(appId int, envId int) (*chartRepoRepository.Chart, error) { +// FetchLatestChartVersion provides a mock function with given fields: appId, envId +func (_m *CommonService) FetchLatestChartVersion(appId int, envId int) (string, error) { ret := _m.Called(appId, envId) - var r0 *chartRepoRepository.Chart + if len(ret) == 0 { + panic("no return value specified for FetchLatestChartVersion") + } + + var r0 string var r1 error - if rf, ok := ret.Get(0).(func(int, int) (*chartRepoRepository.Chart, error)); ok { + if rf, ok := ret.Get(0).(func(int, int) (string, error)); ok { return rf(appId, envId) } - if rf, ok := ret.Get(0).(func(int, int) *chartRepoRepository.Chart); ok { + if rf, ok := ret.Get(0).(func(int, int) string); ok { r0 = rf(appId, envId) } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*chartRepoRepository.Chart) - } + r0 = ret.Get(0).(string) } if rf, ok := ret.Get(1).(func(int, int) error); ok { @@ -44,6 +44,10 @@ func (_m *CommonService) FetchLatestChart(appId int, envId int) (*chartRepoRepos func (_m *CommonService) GlobalChecklist() (*commonService.GlobalChecklist, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GlobalChecklist") + } + var r0 *commonService.GlobalChecklist var r1 error if rf, ok := ret.Get(0).(func() (*commonService.GlobalChecklist, error)); ok { @@ -66,13 +70,12 @@ func (_m *CommonService) GlobalChecklist() (*commonService.GlobalChecklist, erro return r0, r1 } -type mockConstructorTestingTNewCommonService interface { +// NewCommonService creates a new instance of CommonService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewCommonService(t interface { mock.TestingT Cleanup(func()) -} - -// NewCommonService creates a new instance of CommonService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewCommonService(t mockConstructorTestingTNewCommonService) *CommonService { +}) *CommonService { mock := &CommonService{} mock.Mock.Test(t) diff --git a/pkg/configDiff/DeploymentConfigurationService.go b/pkg/config/configDiff/DeploymentConfigurationService.go similarity index 99% rename from pkg/configDiff/DeploymentConfigurationService.go rename to pkg/config/configDiff/DeploymentConfigurationService.go index f591a6cb69..e820fd2827 100644 --- a/pkg/configDiff/DeploymentConfigurationService.go +++ b/pkg/config/configDiff/DeploymentConfigurationService.go @@ -19,10 +19,10 @@ import ( bean3 "github.com/devtron-labs/devtron/pkg/bean" chartService "github.com/devtron-labs/devtron/pkg/chart" repository4 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" - "github.com/devtron-labs/devtron/pkg/configDiff/adaptor" - bean2 "github.com/devtron-labs/devtron/pkg/configDiff/bean" - "github.com/devtron-labs/devtron/pkg/configDiff/helper" - "github.com/devtron-labs/devtron/pkg/configDiff/utils" + "github.com/devtron-labs/devtron/pkg/config/configDiff/adaptor" + bean2 "github.com/devtron-labs/devtron/pkg/config/configDiff/bean" + "github.com/devtron-labs/devtron/pkg/config/configDiff/helper" + "github.com/devtron-labs/devtron/pkg/config/configDiff/utils" "github.com/devtron-labs/devtron/pkg/deployment/manifest/configMapAndSecret" read2 "github.com/devtron-labs/devtron/pkg/deployment/manifest/configMapAndSecret/read" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef" @@ -80,7 +80,6 @@ type DeploymentConfigurationServiceImpl struct { k8sUtil k8sUtil.K8sService mergeUtil util.MergeUtil HelmAppReadService read3.HelmAppReadService - } func NewDeploymentConfigurationServiceImpl(logger *zap.SugaredLogger, diff --git a/pkg/configDiff/DeploymentConfigurationService_ent.go b/pkg/config/configDiff/DeploymentConfigurationService_ent.go similarity index 93% rename from pkg/configDiff/DeploymentConfigurationService_ent.go rename to pkg/config/configDiff/DeploymentConfigurationService_ent.go index 1daf4f0cfd..91cfc30ae0 100644 --- a/pkg/configDiff/DeploymentConfigurationService_ent.go +++ b/pkg/config/configDiff/DeploymentConfigurationService_ent.go @@ -3,7 +3,7 @@ package configDiff import ( "context" "github.com/devtron-labs/devtron/internal/util" - bean2 "github.com/devtron-labs/devtron/pkg/configDiff/bean" + bean2 "github.com/devtron-labs/devtron/pkg/config/configDiff/bean" "github.com/devtron-labs/devtron/pkg/resourceQualifiers" "net/http" ) diff --git a/pkg/configDiff/adaptor/adaptor.go b/pkg/config/configDiff/adaptor/adaptor.go similarity index 97% rename from pkg/configDiff/adaptor/adaptor.go rename to pkg/config/configDiff/adaptor/adaptor.go index 6fd46129fe..32f65e9392 100644 --- a/pkg/configDiff/adaptor/adaptor.go +++ b/pkg/config/configDiff/adaptor/adaptor.go @@ -2,7 +2,7 @@ package adaptor import ( bean3 "github.com/devtron-labs/devtron/pkg/bean" - bean2 "github.com/devtron-labs/devtron/pkg/configDiff/bean" + bean2 "github.com/devtron-labs/devtron/pkg/config/configDiff/bean" "github.com/devtron-labs/devtron/pkg/pipeline/adapter" "github.com/devtron-labs/devtron/pkg/pipeline/bean" ) diff --git a/pkg/configDiff/bean/bean.go b/pkg/config/configDiff/bean/bean.go similarity index 100% rename from pkg/configDiff/bean/bean.go rename to pkg/config/configDiff/bean/bean.go diff --git a/pkg/configDiff/helper/helper.go b/pkg/config/configDiff/helper/helper.go similarity index 94% rename from pkg/configDiff/helper/helper.go rename to pkg/config/configDiff/helper/helper.go index 952914157c..c5afad8ed0 100644 --- a/pkg/configDiff/helper/helper.go +++ b/pkg/config/configDiff/helper/helper.go @@ -3,8 +3,8 @@ package helper import ( "encoding/json" bean3 "github.com/devtron-labs/devtron/pkg/bean" - bean2 "github.com/devtron-labs/devtron/pkg/configDiff/bean" - "github.com/devtron-labs/devtron/pkg/configDiff/utils" + bean2 "github.com/devtron-labs/devtron/pkg/config/configDiff/bean" + "github.com/devtron-labs/devtron/pkg/config/configDiff/utils" "github.com/devtron-labs/devtron/pkg/pipeline/bean" ) diff --git a/pkg/configDiff/utils/utils.go b/pkg/config/configDiff/utils/utils.go similarity index 98% rename from pkg/configDiff/utils/utils.go rename to pkg/config/configDiff/utils/utils.go index de69021f4f..faf81a06e0 100644 --- a/pkg/configDiff/utils/utils.go +++ b/pkg/config/configDiff/utils/utils.go @@ -2,7 +2,7 @@ package utils import ( "encoding/json" - bean2 "github.com/devtron-labs/devtron/pkg/configDiff/bean" + bean2 "github.com/devtron-labs/devtron/pkg/config/configDiff/bean" "github.com/devtron-labs/devtron/pkg/pipeline/bean" "strings" ) diff --git a/pkg/config/read/ConfigReadService.go b/pkg/config/read/ConfigReadService.go new file mode 100644 index 0000000000..67db3c4365 --- /dev/null +++ b/pkg/config/read/ConfigReadService.go @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package read + +import ( + "encoding/json" + apiBean "github.com/devtron-labs/devtron/api/bean" + configMapRepository "github.com/devtron-labs/devtron/internal/sql/repository/chartConfig" + internalUtil "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/commonService" + configMapBean "github.com/devtron-labs/devtron/pkg/pipeline/bean" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" + "github.com/devtron-labs/devtron/pkg/variables" + "go.uber.org/zap" +) + +type ConfigReadService interface { + GetCmCsForPrePostStageTrigger(scope resourceQualifiers.Scope, appId int, envId int, isJob bool) (*apiBean.ConfigMapJson, *apiBean.ConfigSecretJson, error) +} + +type ConfigReadServiceImpl struct { + logger *zap.SugaredLogger + commonService commonService.CommonService + configMapRepository configMapRepository.ConfigMapRepository + mergeUtil internalUtil.MergeUtil + scopedVariableManager variables.ScopedVariableCMCSManager +} + +func NewConfigReadServiceImpl(logger *zap.SugaredLogger, commonService commonService.CommonService, + configMapRepository configMapRepository.ConfigMapRepository, mergeUtil internalUtil.MergeUtil, + scopedVariableManager variables.ScopedVariableCMCSManager) *ConfigReadServiceImpl { + return &ConfigReadServiceImpl{ + logger: logger, + commonService: commonService, + configMapRepository: configMapRepository, + mergeUtil: mergeUtil, + scopedVariableManager: scopedVariableManager, + } +} + +func (impl *ConfigReadServiceImpl) GetCmCsForPrePostStageTrigger(scope resourceQualifiers.Scope, appId int, envId int, isJob bool) (*apiBean.ConfigMapJson, *apiBean.ConfigSecretJson, error) { + appLevelConfig, err := impl.configMapRepository.GetByAppIdAppLevel(appId) + if err != nil && !internalUtil.IsErrNoRows(err) { + impl.logger.Errorw("error while fetching app level config", "appId", appId, "error", err) + return nil, nil, err + } + envLevelConfig, err := impl.configMapRepository.GetByAppIdAndEnvIdEnvLevel(appId, envId) + if err != nil && !internalUtil.IsErrNoRows(err) { + impl.logger.Errorw("error while fetching env level config", "appId", appId, "envId", envId, "error", err) + return nil, nil, err + } + request := configMapBean.NewResolvedCmCsRequest(scope). + WithAppId(appId).WithEnvId(envId).ForJob(isJob) + return impl.getResolvedCmCsForPrePostStageTrigger(request, appLevelConfig, envLevelConfig) +} + +func (impl *ConfigReadServiceImpl) getResolvedCmCsForPrePostStageTrigger(request *configMapBean.ResolvedCmCsRequest, + appLevelConfig *configMapRepository.ConfigMapAppModel, envLevelConfig *configMapRepository.ConfigMapEnvModel) (*apiBean.ConfigMapJson, *apiBean.ConfigSecretJson, error) { + var secretDataJsonApp string + var configMapJsonApp string + if appLevelConfig != nil && appLevelConfig.Id > 0 { + configMapJsonApp = appLevelConfig.ConfigMapData + secretDataJsonApp = appLevelConfig.SecretData + } + var secretDataJsonEnv string + var configMapJsonEnv string + if envLevelConfig != nil && envLevelConfig.Id > 0 { + configMapJsonEnv = envLevelConfig.ConfigMapData + secretDataJsonEnv = envLevelConfig.SecretData + } + configMapJson, err := impl.mergeUtil.ConfigMapMerge(configMapJsonApp, configMapJsonEnv) + if err != nil { + return nil, nil, err + } + var secretDataJson string + if request.IsJob { + secretDataJson, err = impl.mergeUtil.ConfigSecretMergeForJob(secretDataJsonApp, secretDataJsonEnv) + if err != nil { + return nil, nil, err + } + } else { + chartVersion, err := impl.commonService.FetchLatestChartVersion(request.AppId, request.EnvId) + if err != nil { + return nil, nil, err + } + secretDataJson, err = impl.mergeUtil.ConfigSecretMergeForCDStages(secretDataJsonApp, secretDataJsonEnv, chartVersion) + if err != nil { + return nil, nil, err + } + } + configResponse := apiBean.ConfigMapJson{} + if configMapJson != "" { + err = json.Unmarshal([]byte(configMapJson), &configResponse) + if err != nil { + return nil, nil, err + } + } + secretResponse := apiBean.ConfigSecretJson{} + if configMapJson != "" { + err = json.Unmarshal([]byte(secretDataJson), &secretResponse) + if err != nil { + return nil, nil, err + } + } + var appLevelConfigId, envLevelConfigId int + if appLevelConfig != nil { + appLevelConfigId = appLevelConfig.Id + } + if envLevelConfig != nil { + envLevelConfigId = envLevelConfig.Id + } + resolvedConfigResponse, resolvedSecretResponse, err := impl.scopedVariableManager.ResolveForPrePostStageTrigger(request.Scope, configResponse, secretResponse, appLevelConfigId, envLevelConfigId) + if err != nil { + return nil, nil, err + } + return resolvedConfigResponse, resolvedSecretResponse, nil +} diff --git a/pkg/config/wire_config.go b/pkg/config/wire_config.go new file mode 100644 index 0000000000..219885922d --- /dev/null +++ b/pkg/config/wire_config.go @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "github.com/devtron-labs/devtron/pkg/config/read" + "github.com/google/wire" +) + +var WireSet = wire.NewSet( + read.NewConfigReadServiceImpl, + wire.Bind(new(read.ConfigReadService), new(*read.ConfigReadServiceImpl)), +) diff --git a/pkg/deployment/manifest/ManifestCreationService.go b/pkg/deployment/manifest/ManifestCreationService.go index 28a8e3dd3a..d58179f646 100644 --- a/pkg/deployment/manifest/ManifestCreationService.go +++ b/pkg/deployment/manifest/ManifestCreationService.go @@ -24,7 +24,7 @@ import ( application3 "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" k8sUtil "github.com/devtron-labs/common-lib/utils/k8s" "github.com/devtron-labs/devtron/api/bean" - application2 "github.com/devtron-labs/devtron/client/argocdServer/application" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/internal/sql/models" "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/internal/sql/repository/chartConfig" @@ -85,7 +85,7 @@ type ManifestCreationServiceImpl struct { appCrudOperationService app.AppCrudOperationService deploymentTemplateService deploymentTemplate.DeploymentTemplateService - acdClient application2.ServiceClient //TODO: replace with argoClientWrapperService + acdClientWrapper argocdServer.ArgoClientWrapperService configMapHistoryRepository repository3.ConfigMapHistoryRepository configMapRepository chartConfig.ConfigMapRepository @@ -112,7 +112,7 @@ func NewManifestCreationServiceImpl(logger *zap.SugaredLogger, mergeUtil *util.MergeUtil, appCrudOperationService app.AppCrudOperationService, deploymentTemplateService deploymentTemplate.DeploymentTemplateService, - acdClient application2.ServiceClient, + acdClientWrapper argocdServer.ArgoClientWrapperService, configMapHistoryRepository repository3.ConfigMapHistoryRepository, configMapRepository chartConfig.ConfigMapRepository, chartRepository chartRepoRepository.ChartRepository, @@ -138,7 +138,7 @@ func NewManifestCreationServiceImpl(logger *zap.SugaredLogger, appCrudOperationService: appCrudOperationService, deploymentTemplateService: deploymentTemplateService, configMapRepository: configMapRepository, - acdClient: acdClient, + acdClientWrapper: acdClientWrapper, configMapHistoryRepository: configMapHistoryRepository, chartRepository: chartRepository, environmentConfigRepository: environmentConfigRepository, @@ -633,12 +633,7 @@ func (impl *ManifestCreationServiceImpl) getConfigMapAndSecretJsonV2(ctx context if err != nil { return cmAndCsJsonV2Response, err } - chartMajorVersion, chartMinorVersion, err := globalUtil.ExtractChartVersion(request.ChartVersion) - if err != nil { - impl.logger.Errorw("chart version parsing", "err", err) - return cmAndCsJsonV2Response, err - } - secretDataJson, err = impl.mergeUtil.ConfigSecretMerge(secretDataJsonApp, secretDataJsonEnv, chartMajorVersion, chartMinorVersion, false) + secretDataJson, err = impl.mergeUtil.ConfigSecretMergeForCDStages(secretDataJsonApp, secretDataJsonEnv, request.ChartVersion) if err != nil { return cmAndCsJsonV2Response, err } @@ -894,7 +889,7 @@ func (impl *ManifestCreationServiceImpl) getArgoCdHPAResourceManifest(ctx contex Namespace: &namespace, } - recv, argoErr := impl.acdClient.GetResource(newCtx, query) + recv, argoErr := impl.acdClientWrapper.GetApplicationResource(newCtx, query) if argoErr != nil { grpcCode, errMsg := util.GetClientDetailedError(argoErr) if grpcCode.IsInvalidArgumentCode() || grpcCode.IsNotFoundCode() { diff --git a/pkg/deployment/manifest/configMapAndSecret/read/ConfigMapHistoryReadService.go b/pkg/deployment/manifest/configMapAndSecret/read/ConfigMapHistoryReadService.go index 15e9287f04..0f00d5b946 100644 --- a/pkg/deployment/manifest/configMapAndSecret/read/ConfigMapHistoryReadService.go +++ b/pkg/deployment/manifest/configMapAndSecret/read/ConfigMapHistoryReadService.go @@ -5,9 +5,9 @@ import ( "encoding/json" "errors" bean2 "github.com/devtron-labs/devtron/pkg/bean" - "github.com/devtron-labs/devtron/pkg/configDiff/adaptor" - bean3 "github.com/devtron-labs/devtron/pkg/configDiff/bean" - "github.com/devtron-labs/devtron/pkg/configDiff/utils" + "github.com/devtron-labs/devtron/pkg/config/configDiff/adaptor" + bean3 "github.com/devtron-labs/devtron/pkg/config/configDiff/bean" + "github.com/devtron-labs/devtron/pkg/config/configDiff/utils" "github.com/devtron-labs/devtron/pkg/pipeline/adapter" bean4 "github.com/devtron-labs/devtron/pkg/pipeline/bean" "github.com/devtron-labs/devtron/pkg/pipeline/history/bean" diff --git a/pkg/deployment/trigger/devtronApps/PostStageTriggerService.go b/pkg/deployment/trigger/devtronApps/PostStageTriggerService.go index fa5f04ed6e..b22609e0a8 100644 --- a/pkg/deployment/trigger/devtronApps/PostStageTriggerService.go +++ b/pkg/deployment/trigger/devtronApps/PostStageTriggerService.go @@ -118,6 +118,7 @@ func (impl *TriggerServiceImpl) TriggerPostStage(request bean.TriggerRequest) (* if err != nil { runner.Status = cdWorkflow.WorkflowFailed runner.Message = err.Error() + runner.FinishedOn = time.Now() _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) return nil, err } @@ -125,6 +126,10 @@ func (impl *TriggerServiceImpl) TriggerPostStage(request bean.TriggerRequest) (* _, jobHelmPackagePath, err := impl.cdWorkflowService.SubmitWorkflow(cdStageWorkflowRequest) if err != nil { impl.logger.Errorw("error in submitting workflow", "err", err, "workflowId", cdStageWorkflowRequest.WorkflowId, "pipeline", pipeline, "env", env) + runner.Status = cdWorkflow.WorkflowFailed + runner.Message = err.Error() + runner.FinishedOn = time.Now() + _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) return nil, err } manifestPushTempate, err := impl.getManifestPushTemplateForPostStage(request, envDevploymentConfig, jobHelmPackagePath, cdStageWorkflowRequest, cdWf, runner, pipeline, triggeredBy, triggeredAt) diff --git a/pkg/deployment/trigger/devtronApps/PreStageTriggerService.go b/pkg/deployment/trigger/devtronApps/PreStageTriggerService.go index da0ec9a741..913bd9663d 100644 --- a/pkg/deployment/trigger/devtronApps/PreStageTriggerService.go +++ b/pkg/deployment/trigger/devtronApps/PreStageTriggerService.go @@ -134,6 +134,7 @@ func (impl *TriggerServiceImpl) TriggerPreStage(request bean.TriggerRequest) (*b if err != nil { runner.Status = cdWorkflow.WorkflowFailed runner.Message = err.Error() + runner.FinishedOn = time.Now() _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) return nil, err } else { @@ -148,6 +149,10 @@ func (impl *TriggerServiceImpl) TriggerPreStage(request bean.TriggerRequest) (*b _, jobHelmPackagePath, err := impl.cdWorkflowService.SubmitWorkflow(cdStageWorkflowRequest) span.End() if err != nil { + runner.Status = cdWorkflow.WorkflowFailed + runner.Message = err.Error() + runner.FinishedOn = time.Now() + _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) return nil, err } manifestPushTemplate, err := impl.getManifestPushTemplateForPreStage(ctx, envDeploymentConfig, pipeline, artifact, jobHelmPackagePath, cdWf, runner, triggeredBy, triggeredAt, request) diff --git a/pkg/eventProcessor/bean/workflowEventBean.go b/pkg/eventProcessor/bean/workflowEventBean.go index 316bbf7613..8bcd4f200c 100644 --- a/pkg/eventProcessor/bean/workflowEventBean.go +++ b/pkg/eventProcessor/bean/workflowEventBean.go @@ -83,6 +83,7 @@ type CiCompleteEvent struct { PluginRegistryArtifactDetails map[string][]string `json:"PluginRegistryArtifactDetails"` PluginArtifactStage string `json:"pluginArtifactStage"` IsScanEnabled bool `json:"isScanEnabled"` + TargetPlatforms []string `json:"targetPlatforms"` pluginImageDetails *registry.ImageDetailsFromCR PluginArtifacts *PluginArtifacts `json:"pluginArtifacts"` } diff --git a/pkg/eventProcessor/in/WorkflowEventProcessorService.go b/pkg/eventProcessor/in/WorkflowEventProcessorService.go index b3057da86b..631c68c597 100644 --- a/pkg/eventProcessor/in/WorkflowEventProcessorService.go +++ b/pkg/eventProcessor/in/WorkflowEventProcessorService.go @@ -678,6 +678,7 @@ func (impl *WorkflowEventProcessorImpl) BuildCiArtifactRequest(event bean.CiComp PluginRegistryArtifactDetails: pluginArtifacts, PluginArtifactStage: event.PluginArtifactStage, IsScanEnabled: event.IsScanEnabled, + TargetPlatforms: event.TargetPlatforms, } // if DataSource is empty, repository.WEBHOOK is considered as default if request.DataSource == "" { diff --git a/pkg/gitops/GitOpsConfigService.go b/pkg/gitops/GitOpsConfigService.go index d938e47fff..0b7bb6c2f5 100644 --- a/pkg/gitops/GitOpsConfigService.go +++ b/pkg/gitops/GitOpsConfigService.go @@ -26,10 +26,12 @@ import ( util4 "github.com/devtron-labs/common-lib/utils/k8s" "github.com/devtron-labs/devtron/api/bean" apiBean "github.com/devtron-labs/devtron/api/bean/gitOps" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/client/argocdServer/certificate" + config2 "github.com/devtron-labs/devtron/client/argocdServer/config" "github.com/devtron-labs/devtron/client/argocdServer/connection" - repocreds "github.com/devtron-labs/devtron/client/argocdServer/repocreds" repository2 "github.com/devtron-labs/devtron/client/argocdServer/repository" + "github.com/devtron-labs/devtron/pkg/cluster/read" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/validation" @@ -40,10 +42,10 @@ import ( "time" cluster3 "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster" - cluster2 "github.com/devtron-labs/devtron/client/argocdServer/cluster" "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/cluster" + bean2 "github.com/devtron-labs/devtron/pkg/cluster/bean" "github.com/devtron-labs/devtron/pkg/sql" util3 "github.com/devtron-labs/devtron/pkg/util" "github.com/go-pg/pg" @@ -62,50 +64,53 @@ type GitOpsConfigService interface { } type GitOpsConfigServiceImpl struct { - logger *zap.SugaredLogger - gitOpsRepository repository.GitOpsConfigRepository - K8sUtil *util4.K8sServiceImpl - aCDAuthConfig *util3.ACDAuthConfig - clusterService cluster.ClusterService - clusterServiceCD cluster2.ServiceClient - gitOpsConfigReadService config.GitOpsConfigReadService - gitOperationService git.GitOperationService - gitOpsValidationService validation.GitOpsValidationService - argoCertificateClient certificate.Client - argoRepoService repository2.ServiceClient - repocreds repocreds.ServiceClient - devtronSecretConfig *util2.DevtronSecretConfig - argoCDConnectionManager connection.ArgoCDConnectionManager + logger *zap.SugaredLogger + gitOpsRepository repository.GitOpsConfigRepository + K8sUtil *util4.K8sServiceImpl + aCDAuthConfig *util3.ACDAuthConfig + clusterService cluster.ClusterService + gitOpsConfigReadService config.GitOpsConfigReadService + gitOperationService git.GitOperationService + gitOpsValidationService validation.GitOpsValidationService + argoCertificateClient certificate.ServiceClient + argoRepoService repository2.ServiceClient + devtronSecretConfig *util2.DevtronSecretConfig + argoCDConnectionManager connection.ArgoCDConnectionManager + argoCDConfigGetter config2.ArgoCDConfigGetter + argoClientWrapperService argocdServer.ArgoClientWrapperService + clusterReadService read.ClusterReadService } func NewGitOpsConfigServiceImpl(Logger *zap.SugaredLogger, gitOpsRepository repository.GitOpsConfigRepository, K8sUtil *util4.K8sServiceImpl, aCDAuthConfig *util3.ACDAuthConfig, clusterService cluster.ClusterService, - clusterServiceCD cluster2.ServiceClient, gitOperationService git.GitOperationService, gitOpsConfigReadService config.GitOpsConfigReadService, gitOpsValidationService validation.GitOpsValidationService, - argoCertificateClient certificate.Client, + argoCertificateClient certificate.ServiceClient, argoRepoService repository2.ServiceClient, - repocreds repocreds.ServiceClient, environmentVariables *util2.EnvironmentVariables, - argoCDConnectionManager connection.ArgoCDConnectionManager) *GitOpsConfigServiceImpl { + argoCDConnectionManager connection.ArgoCDConnectionManager, + argoCDConfigGetter config2.ArgoCDConfigGetter, + argoClientWrapperService argocdServer.ArgoClientWrapperService, + clusterReadService read.ClusterReadService) *GitOpsConfigServiceImpl { return &GitOpsConfigServiceImpl{ - logger: Logger, - gitOpsRepository: gitOpsRepository, - K8sUtil: K8sUtil, - aCDAuthConfig: aCDAuthConfig, - clusterService: clusterService, - clusterServiceCD: clusterServiceCD, - gitOpsConfigReadService: gitOpsConfigReadService, - gitOperationService: gitOperationService, - gitOpsValidationService: gitOpsValidationService, - argoCertificateClient: argoCertificateClient, - argoRepoService: argoRepoService, - repocreds: repocreds, - devtronSecretConfig: environmentVariables.DevtronSecretConfig, - argoCDConnectionManager: argoCDConnectionManager, + logger: Logger, + gitOpsRepository: gitOpsRepository, + K8sUtil: K8sUtil, + aCDAuthConfig: aCDAuthConfig, + clusterService: clusterService, + gitOpsConfigReadService: gitOpsConfigReadService, + gitOperationService: gitOperationService, + gitOpsValidationService: gitOpsValidationService, + argoCertificateClient: argoCertificateClient, + argoRepoService: argoRepoService, + devtronSecretConfig: environmentVariables.DevtronSecretConfig, + argoCDConnectionManager: argoCDConnectionManager, + argoCDConfigGetter: argoCDConfigGetter, + argoClientWrapperService: argoClientWrapperService, + clusterReadService: clusterReadService, } } @@ -113,8 +118,13 @@ func (impl *GitOpsConfigServiceImpl) ValidateAndCreateGitOpsConfig(config *apiBe detailedErrorGitOpsConfigResponse := impl.GitOpsValidateDryRun(config) if len(detailedErrorGitOpsConfigResponse.StageErrorMap) == 0 { //create argo-cd user, if not created, here argo-cd integration has to be installed - _ = impl.argoCDConnectionManager.GetOrUpdateArgoCdUserDetail() - _, err := impl.createGitOpsConfig(context.Background(), config) + gRPCConfig, err := impl.argoCDConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting all grpc configs", "error", err) + return detailedErrorGitOpsConfigResponse, err + } + _ = impl.argoCDConnectionManager.GetOrUpdateArgoCdUserDetail(gRPCConfig) + _, err = impl.createGitOpsConfig(context.Background(), config) if err != nil { impl.logger.Errorw("service err, SaveGitRepoConfig", "err", err, "payload", config) return detailedErrorGitOpsConfigResponse, err @@ -166,7 +176,13 @@ func (impl *GitOpsConfigServiceImpl) ValidateAndUpdateGitOpsConfig(config *apiBe } } } - _ = impl.argoCDConnectionManager.GetOrUpdateArgoCdUserDetail() + gRPCConfig, err := impl.argoCDConfigGetter.GetGRPCConfig() + if err != nil { + impl.logger.Errorw("error in getting all grpc configs", "error", err) + return apiBean.DetailedErrorGitOpsConfigResponse{}, err + } + _ = impl.argoCDConnectionManager.GetOrUpdateArgoCdUserDetail(gRPCConfig) + detailedErrorGitOpsConfigResponse := impl.GitOpsValidateDryRun(config) if len(detailedErrorGitOpsConfigResponse.StageErrorMap) == 0 { err := impl.updateGitOpsConfig(config) @@ -179,7 +195,7 @@ func (impl *GitOpsConfigServiceImpl) ValidateAndUpdateGitOpsConfig(config *apiBe } // step-1: save data in DB -// step-3: add ca cert if present to list of trusted certificates on argoCD using certificate.Client service +// step-3: add ca cert if present to list of trusted certificates on argoCD using certificate.ServiceClient service // step-3: add repository credentials in secret declared using env variable GITOPS_SECRET_NAME // step-4 add repository URL in argocd-cm, argocd-cm will have reference to secret created in step-3 for credentials // steps-5 upsert cluster in acd @@ -283,7 +299,7 @@ func (impl *GitOpsConfigServiceImpl) createGitOpsConfig(ctx context.Context, req if err != nil { return nil, err } - _, err = impl.repocreds.CreateRepoCreds(ctx, &repocreds2.RepoCredsCreateRequest{ + _, err = impl.argoClientWrapperService.CreateRepoCreds(ctx, &repocreds2.RepoCredsCreateRequest{ Creds: &v1alpha1.RepoCreds{ URL: request.Host, Username: model.Username, @@ -306,7 +322,7 @@ func (impl *GitOpsConfigServiceImpl) createGitOpsConfig(ctx context.Context, req } else { - clusterBean, err := impl.clusterService.FindOne(cluster.DEFAULT_CLUSTER) + clusterBean, err := impl.clusterReadService.FindOne(bean2.DEFAULT_CLUSTER) if err != nil { return nil, err } @@ -402,7 +418,7 @@ func (impl *GitOpsConfigServiceImpl) createGitOpsConfig(ctx context.Context, req } for _, cluster := range clusters { cl := impl.clusterService.ConvertClusterBeanObjectToCluster(&cluster) - _, err = impl.clusterServiceCD.Create(ctx, &cluster3.ClusterCreateRequest{Upsert: true, Cluster: cl}) + _, err = impl.argoClientWrapperService.CreateCluster(ctx, &cluster3.ClusterCreateRequest{Upsert: true, Cluster: cl}) if err != nil { impl.logger.Errorw("Error while upserting cluster in acd", "clusterName", cluster.ClusterName, "err", err) return nil, err @@ -431,7 +447,7 @@ func (impl *GitOpsConfigServiceImpl) addCACertInArgoIfPresent(ctx context.Contex impl.logger.Errorw("invalid gitOps host", "host", host, "err", err) return err } - _, err = impl.argoCertificateClient.CreateCertificate(ctx, &certificate2.RepositoryCertificateCreateRequest{ + _, err = impl.argoClientWrapperService.CreateCertificate(ctx, &certificate2.RepositoryCertificateCreateRequest{ Certificates: &v1alpha1.RepositoryCertificateList{ Items: []v1alpha1.RepositoryCertificate{{ ServerName: host, @@ -568,7 +584,7 @@ func (impl *GitOpsConfigServiceImpl) updateGitOpsConfig(request *apiBean.GitOpsC return err } - _, err = impl.repocreds.CreateRepoCreds(context.Background(), &repocreds2.RepoCredsCreateRequest{ + _, err = impl.argoClientWrapperService.CreateRepoCreds(context.Background(), &repocreds2.RepoCredsCreateRequest{ Creds: &v1alpha1.RepoCreds{ URL: request.Host, Username: model.Username, @@ -590,7 +606,7 @@ func (impl *GitOpsConfigServiceImpl) updateGitOpsConfig(request *apiBean.GitOpsC } } else { - clusterBean, err := impl.clusterService.FindOne(cluster.DEFAULT_CLUSTER) + clusterBean, err := impl.clusterReadService.FindOne(bean2.DEFAULT_CLUSTER) if err != nil { return err } diff --git a/pkg/infraConfig/adapter/adapter.go b/pkg/infraConfig/adapter/adapter.go index 8faee3338a..951434adf9 100644 --- a/pkg/infraConfig/adapter/adapter.go +++ b/pkg/infraConfig/adapter/adapter.go @@ -1,238 +1,127 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package adapter import ( - "errors" - "fmt" - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v0" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" "github.com/devtron-labs/devtron/pkg/infraConfig/repository" - "github.com/devtron-labs/devtron/pkg/infraConfig/units" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" "github.com/devtron-labs/devtron/pkg/infraConfig/util" "github.com/devtron-labs/devtron/pkg/sql" - util2 "github.com/devtron-labs/devtron/util" - "math" - "strconv" + "slices" ) -func ConvertToPlatformMap(infraProfileConfigurationEntities []*repository.InfraProfileConfigurationEntity, profileName string) (map[string][]*bean.ConfigurationBean, error) { - // Validate input parameters - if len(infraProfileConfigurationEntities) == 0 { - return nil, fmt.Errorf("input infraProfileConfigurationEntities is empty") - } - if profileName == "" { - return nil, fmt.Errorf("profileName cannot be empty") - } - platformMap := make(map[string][]*bean.ConfigurationBean) - for _, infraProfileConfiguration := range infraProfileConfigurationEntities { - if infraProfileConfiguration == nil { - return nil, fmt.Errorf("infraProfileConfiguration for profile %s is nil", profileName) - } - - configurationBean, err := GetConfigurationBean(infraProfileConfiguration, profileName) - if err != nil { - return nil, fmt.Errorf("failed to get configuration bean for profile from infraConfiguration '%s': %w", profileName, err) - } - platform := infraProfileConfiguration.ProfilePlatformMapping.Platform - if len(platform) == 0 { - platform = bean.RUNNER_PLATFORM - } - - // Add the ConfigurationBean to the corresponding platform entry in the map - platformMap[platform] = append(platformMap[platform], configurationBean) - } - return platformMap, nil -} - -// ConvertFromPlatformMap converts map[platform][]*ConfigurationBean back to []InfraProfileConfigurationEntity -func ConvertFromPlatformMap(platformMap map[string][]*bean.ConfigurationBean, profileBean *bean.ProfileBeanDto, userId int32) []*repository.InfraProfileConfigurationEntity { - var entities []*repository.InfraProfileConfigurationEntity - for platform, beans := range platformMap { - for _, configBean := range beans { - entity := getInfraProfileEntity(configBean, profileBean, platform, userId) - entities = append(entities, entity) - } - } - return entities -} - -// Function to convert valueString to interface{} based on key -func convertValueStringToInterface(configKey bean.ConfigKeyStr, valueString string) (interface{}, error) { - switch configKey { - case bean.CPU_LIMIT, bean.CPU_REQUEST, bean.MEMORY_LIMIT, bean.MEMORY_REQUEST: - // Convert string to float64 and truncate to 2 decimal places - valueFloat, err := strconv.ParseFloat(valueString, 64) - truncateValue := util2.TruncateFloat(valueFloat, 2) - return truncateValue, err // Returning float64 for resource values - case bean.TIME_OUT: - // Convert string to float64 and ensure it's within integer range - valueFloat, err := strconv.ParseFloat(valueString, 64) - modifiedValue := math.Min(math.Floor(valueFloat), math.MaxInt64) - return modifiedValue, err // Returning float64 for timeout - - // Add more cases as needed for different config keys - default: - // Default case, return the string as is - err := errors.New(fmt.Sprintf("unsupported key found %s", configKey)) - return nil, err - } -} - -func GetConfigurationBean(infraProfileConfiguration *repository.InfraProfileConfigurationEntity, profileName string) (*bean.ConfigurationBean, error) { - valueString := infraProfileConfiguration.ValueString - //handle old values - if len(valueString) == 0 && infraProfileConfiguration.Unit > 0 { - valueString = strconv.FormatFloat(infraProfileConfiguration.Value, 'f', -1, 64) - } - valueInterface, err := convertValueStringToInterface(utils.GetConfigKeyStr(infraProfileConfiguration.Key), valueString) - if err != nil { - return &bean.ConfigurationBean{}, err - } - return &bean.ConfigurationBean{ - ConfigurationBeanAbstract: bean.ConfigurationBeanAbstract{ - Id: infraProfileConfiguration.Id, - Key: utils.GetConfigKeyStr(infraProfileConfiguration.Key), - Unit: utils.GetUnitSuffixStr(infraProfileConfiguration.Key, infraProfileConfiguration.Unit), - Active: infraProfileConfiguration.Active, - ProfileId: infraProfileConfiguration.ProfilePlatformMapping.ProfileId, - ProfileName: profileName, - ProfilePlatformMappingId: infraProfileConfiguration.ProfilePlatformMapping.Id, - }, - Value: valueInterface, - }, nil -} - -func getInfraProfileEntity(configurationBean *bean.ConfigurationBean, profileBean *bean.ProfileBeanDto, platform string, userId int32) *repository.InfraProfileConfigurationEntity { - +func GetInfraProfileEntity(configurationBean *v1.ConfigurationBean, valueString, platform string, userId int32) *repository.InfraProfileConfigurationEntity { infraProfile := &repository.InfraProfileConfigurationEntity{ Id: configurationBean.Id, - Key: utils.GetConfigKey(configurationBean.Key), - ValueString: FormatTypedValueAsString(configurationBean.Key, configurationBean.Value), - Unit: utils.GetUnitSuffix(configurationBean.Key, configurationBean.Unit), + Key: util.GetConfigKey(configurationBean.Key), + ValueString: valueString, + Unit: util.GetUnitSuffix(configurationBean.Key, configurationBean.Unit), + ProfileId: configurationBean.ProfileId, // maintained for backward compatibility + UniqueId: repository.GetUniqueId(configurationBean.ProfileId, platform), Active: configurationBean.Active, - UniqueId: repository.GetUniqueId(profileBean.Id, platform), - ProfileId: profileBean.Id, // maintained for backward compatibility + AuditLog: sql.NewDefaultAuditLog(userId), ProfilePlatformMapping: &repository.ProfilePlatformMapping{ - ProfileId: profileBean.Id, + ProfileId: configurationBean.ProfileId, Platform: platform, }, - AuditLog: sql.NewDefaultAuditLog(userId), } - setProfilePlatformMappingId(profileBean, infraProfile) - if profileBean.Name == bean.GLOBAL_PROFILE_NAME { + if configurationBean.ProfileName == v1.GLOBAL_PROFILE_NAME { infraProfile.Active = true } return infraProfile } -func FormatTypedValueAsString(configKey bean.ConfigKeyStr, configValue interface{}) string { - if configKey == bean.CPU_LIMIT || - configKey == bean.CPU_REQUEST || - configKey == bean.MEMORY_LIMIT || - configKey == bean.MEMORY_REQUEST { - var valueFloat float64 - // Handle string input or directly as float64 - switch v := configValue.(type) { - case string: - valueFloat, _ = strconv.ParseFloat(v, 64) - case float64: - valueFloat = v - } - // Truncate and format the float value - truncateValue := util2.TruncateFloat(valueFloat, 2) - return strconv.FormatFloat(truncateValue, 'f', -1, 64) - //valueFloat, _ := strconv.ParseFloat(configValue.(float64), 64) - } - - if configKey == bean.TIME_OUT { - var valueFloat float64 - switch v := configValue.(type) { - case string: - valueFloat, _ = strconv.ParseFloat(v, 64) - case float64: - valueFloat = v - } - //valueFloat, _ := strconv.ParseFloat(configValue, 64) - modifiedValue := math.Min(math.Floor(valueFloat), math.MaxInt64) - return strconv.FormatFloat(modifiedValue, 'f', -1, 64) - } - - return configValue.(string) -} - -func GetV0ProfileBean(profileBean *bean.ProfileBeanDto) *bean.ProfileBeanV0 { +// Deprecated: GetV0ProfileBean is used for backward compatibility with V0. +// Only used for deprecated APIs. +func GetV0ProfileBean(profileBean *v1.ProfileBeanDto) *v0.ProfileBeanV0 { if profileBean == nil { - return &bean.ProfileBeanV0{} - } - profileName := profileBean.Name - if profileName == bean.GLOBAL_PROFILE_NAME { - profileName = bean.DEFAULT_PROFILE_NAME + return &v0.ProfileBeanV0{} } - profileType := profileBean.Type - if profileType == bean.GLOBAL { - profileType = bean.DEFAULT + profileName := profileBean.GetName() + if profileName == v1.GLOBAL_PROFILE_NAME { + profileName = v1.DEFAULT_PROFILE_NAME } - ciRunnerConfig := profileBean.Configurations[bean.RUNNER_PLATFORM] - return &bean.ProfileBeanV0{ - ProfileBeanAbstract: bean.ProfileBeanAbstract{ - Id: profileBean.Id, - Name: profileName, - Description: profileBean.Description, - BuildxDriverType: profileBean.BuildxDriverType, - Active: profileBean.Active, - Type: profileType, - AppCount: profileBean.AppCount, - CreatedBy: profileBean.CreatedBy, - CreatedOn: profileBean.CreatedOn, - UpdatedBy: profileBean.UpdatedBy, - UpdatedOn: profileBean.UpdatedOn, + profileType := profileBean.Type + if profileType == v1.GLOBAL { + profileType = v1.DEFAULT + } + + ciRunnerConfig := profileBean.GetConfigurations()[v1.RUNNER_PLATFORM] + profileV0Bean := &v0.ProfileBeanV0{ + ProfileBeanAbstract: v1.ProfileBeanAbstract{ + Id: profileBean.Id, + Name: profileName, + Description: profileBean.GetDescription(), + Active: profileBean.Active, + Type: profileType, + AppCount: profileBean.AppCount, }, - Configurations: GetV0ConfigurationBeans(ciRunnerConfig), - } + Configurations: ConvertToV0ConfigBeans(ciRunnerConfig), + } + profileV0Bean.BuildxDriverType = profileBean.GetBuildxDriverType() + return profileV0Bean } -func GetV1ProfileBean(profileBean *bean.ProfileBeanV0) *bean.ProfileBeanDto { +// ConvertToV1ProfileBean converts V0 ProfileBean to V1 ProfileBean +// Only used for deprecated APIs handling. +func ConvertToV1ProfileBean(profileBean *v0.ProfileBeanV0) *v1.ProfileBeanDto { if profileBean == nil { return nil } - profileName := profileBean.Name - if profileName == bean.DEFAULT_PROFILE_NAME { - profileName = bean.GLOBAL_PROFILE_NAME + profileName := profileBean.GetName() + if profileName == v1.DEFAULT_PROFILE_NAME { + profileName = v1.GLOBAL_PROFILE_NAME } profileType := profileBean.Type - if profileType == bean.DEFAULT { - profileType = bean.GLOBAL - } - return &bean.ProfileBeanDto{ - ProfileBeanAbstract: bean.ProfileBeanAbstract{ - Id: profileBean.Id, - Name: profileName, - Description: profileBean.Description, - Active: profileBean.Active, - Type: profileType, - AppCount: profileBean.AppCount, - CreatedBy: profileBean.CreatedBy, - CreatedOn: profileBean.CreatedOn, - UpdatedBy: profileBean.UpdatedBy, - UpdatedOn: profileBean.UpdatedOn, - BuildxDriverType: profileBean.BuildxDriverType, + if profileType == v1.GLOBAL { + profileType = v1.DEFAULT + } + newProfileBean := &v1.ProfileBeanDto{ + ProfileBeanAbstract: v1.ProfileBeanAbstract{ + Id: profileBean.Id, + Name: profileName, + Description: profileBean.GetDescription(), + Active: profileBean.Active, + Type: profileType, + AppCount: profileBean.AppCount, }, - Configurations: map[string][]*bean.ConfigurationBean{bean.RUNNER_PLATFORM: GetV1ConfigurationBeans(profileBean.Configurations, profileName)}, + Configurations: map[string][]*v1.ConfigurationBean{v1.RUNNER_PLATFORM: getV1ConfigBeans(profileBean.Configurations)}, } - + newProfileBean.BuildxDriverType = profileBean.GetBuildxDriverType() + return newProfileBean } -func GetV1ConfigurationBeans(configBeans []bean.ConfigurationBeanV0, profileName string) []*bean.ConfigurationBean { +func getV1ConfigBeans(configBeans []v0.ConfigurationBeanV0) []*v1.ConfigurationBean { if len(configBeans) == 0 { return nil } - resp := make([]*bean.ConfigurationBean, 0) + resp := make([]*v1.ConfigurationBean, 0) for _, configBean := range configBeans { - valueString := strconv.FormatFloat(configBean.Value, 'f', -1, 64) - - configBeanV1 := &bean.ConfigurationBean{ - ConfigurationBeanAbstract: bean.ConfigurationBeanAbstract{ + profileName := configBean.ProfileName + if profileName == v1.GLOBAL_PROFILE_NAME { + profileName = v1.DEFAULT_PROFILE_NAME + } + configBeanV1 := &v1.ConfigurationBean{ + ConfigurationBeanAbstract: v1.ConfigurationBeanAbstract{ Id: configBean.Id, Key: configBean.Key, Unit: configBean.Unit, @@ -240,35 +129,38 @@ func GetV1ConfigurationBeans(configBeans []bean.ConfigurationBeanV0, profileName ProfileId: configBean.ProfileId, ProfileName: profileName, }, - Value: valueString, + Value: configBean.Value, } resp = append(resp, configBeanV1) } return resp } -func GetV0ConfigurationBeans(configBeans []*bean.ConfigurationBean) []bean.ConfigurationBeanV0 { +// ConvertToV0ConfigBeans converts V1 ConfigurationBean to V0 ConfigurationBean +// Only used for deprecated APIs handling. +func ConvertToV0ConfigBeans(configBeans []*v1.ConfigurationBean) []v0.ConfigurationBeanV0 { if len(configBeans) == 0 { - return []bean.ConfigurationBeanV0{} + return []v0.ConfigurationBeanV0{} } - - resp := make([]bean.ConfigurationBeanV0, 0) + resp := make([]v0.ConfigurationBeanV0, 0) for _, configBean := range configBeans { - // Use the GetTypedValue function to decode the value - typedValue, _ := utils.GetTypedValue(configBean.Key, configBean.Value) + if !slices.Contains(v1.AllConfigKeysV0, configBean.Key) { + // here skipping the value for the NodeSelectors and TolerationsKey + continue + } // Cast the returned value to float64 for supported keys - valueFloat, ok := typedValue.(float64) + valueFloat, ok := configBean.Value.(float64) if !ok { - //here skipping the value for the NodeSelectors and TolerationsKey continue } profileName := configBean.ProfileName - if profileName == bean.GLOBAL_PROFILE_NAME { - profileName = bean.DEFAULT_PROFILE_NAME + if profileName == v1.GLOBAL_PROFILE_NAME { + profileName = v1.DEFAULT_PROFILE_NAME } - beanv0 := bean.ConfigurationBeanV0{ - ConfigurationBeanAbstract: bean.ConfigurationBeanAbstract{ + // Construct the V0 bean + beanv0 := v0.ConfigurationBeanV0{ + ConfigurationBeanAbstract: v1.ConfigurationBeanAbstract{ Id: configBean.Id, Key: configBean.Key, Unit: configBean.Unit, @@ -280,142 +172,105 @@ func GetV0ConfigurationBeans(configBeans []*bean.ConfigurationBean) []bean.Confi } resp = append(resp, beanv0) } + return resp } -func ConvertToProfileBean(infraProfile *repository.InfraProfileEntity) bean.ProfileBeanDto { - profileType := bean.GLOBAL - if infraProfile.Name != bean.GLOBAL_PROFILE_NAME { - profileType = bean.NORMAL - } - return bean.ProfileBeanDto{ - ProfileBeanAbstract: bean.ProfileBeanAbstract{ - Id: infraProfile.Id, - Name: infraProfile.Name, - Type: profileType, - Description: infraProfile.Description, - BuildxDriverType: infraProfile.BuildxDriverType, - Active: infraProfile.Active, - CreatedBy: infraProfile.CreatedBy, - CreatedOn: infraProfile.CreatedOn, - UpdatedBy: infraProfile.UpdatedBy, - UpdatedOn: infraProfile.UpdatedOn, +// ConvertToProfileBean converts *repository.InfraProfileEntity to *bean.ProfileBeanDto +func ConvertToProfileBean(infraProfile *repository.InfraProfileEntity) *v1.ProfileBeanDto { + profileType := v1.GLOBAL + if infraProfile.Name != v1.GLOBAL_PROFILE_NAME { + profileType = v1.NORMAL + } + newProfileBean := &v1.ProfileBeanDto{ + ProfileBeanAbstract: v1.ProfileBeanAbstract{ + Id: infraProfile.Id, + Name: infraProfile.Name, + Type: profileType, + Description: infraProfile.Description, + Active: infraProfile.Active, }, } + newProfileBean.BuildxDriverType = infraProfile.BuildxDriverType + return newProfileBean } -func ConvertToInfraProfileEntity(profileBean *bean.ProfileBeanDto) *repository.InfraProfileEntity { +// ConvertToInfraProfileEntity converts *bean.ProfileBeanDto to *repository.InfraProfileEntity +func ConvertToInfraProfileEntity(profileBean *v1.ProfileBeanDto) *repository.InfraProfileEntity { return &repository.InfraProfileEntity{ Id: profileBean.Id, - Name: profileBean.Name, - Description: profileBean.Description, - BuildxDriverType: profileBean.BuildxDriverType, + Name: profileBean.GetName(), + Description: profileBean.GetDescription(), + BuildxDriverType: profileBean.GetBuildxDriverType(), } } -func LoadCiLimitCpu(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { - val, suffix, err := units.ParseValAndUnit(infraConfig.CiLimitCpu) - if err != nil { - return nil, err - } +// NewInfraProfileConfigEntity creates a new instance of repository.InfraProfileConfigurationEntity +// Used for creating new configuration entity for migration. +func NewInfraProfileConfigEntity(key v1.ConfigKeyStr, profileId int, platform string, parsedValue *unitsBean.ParsedValue) *repository.InfraProfileConfigurationEntity { + // Create the DB entity return &repository.InfraProfileConfigurationEntity{ - Key: bean.CPULimitKey, - ValueString: strconv.FormatFloat(val, 'f', -1, 64), - Unit: units.CPUUnitStr(suffix).GetCPUUnit(), + Key: util.GetConfigKey(key), + UniqueId: repository.GetUniqueId(profileId, platform), + Unit: parsedValue.GetUnitType(), + ValueString: parsedValue.GetValueString(), ProfilePlatformMapping: &repository.ProfilePlatformMapping{ - Platform: bean.RUNNER_PLATFORM, + ProfileId: profileId, + Platform: platform, }, - }, nil - -} - -func LoadCiLimitMem(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { - val, suffix, err := units.ParseValAndUnit(infraConfig.CiLimitMem) - if err != nil { - return nil, err } - return &repository.InfraProfileConfigurationEntity{ - Key: bean.MemoryLimitKey, - ValueString: strconv.FormatFloat(val, 'f', -1, 64), - Unit: units.MemoryUnitStr(suffix).GetMemoryUnit(), - ProfilePlatformMapping: &repository.ProfilePlatformMapping{ - Platform: bean.RUNNER_PLATFORM, - }, - }, nil } -func LoadCiReqCpu(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { - val, suffix, err := units.ParseValAndUnit(infraConfig.CiReqCpu) - if err != nil { - return nil, err +// UpdatePlatformMappingInConfigEntities +// - updates the ProfilePlatformMappingId in the repository.InfraProfileConfigurationEntity +func UpdatePlatformMappingInConfigEntities(infraConfigurations []*repository.InfraProfileConfigurationEntity, + platformMappings []*repository.ProfilePlatformMapping) []*repository.InfraProfileConfigurationEntity { + platformMappingId := make(map[string]int) + for _, platformMapping := range platformMappings { + if len(platformMapping.UniqueId) == 0 { + platformMapping.UniqueId = repository.GetUniqueId(platformMapping.ProfileId, platformMapping.Platform) + } + platformMappingId[platformMapping.UniqueId] = platformMapping.Id } - return &repository.InfraProfileConfigurationEntity{ - Key: bean.CPURequestKey, - ValueString: strconv.FormatFloat(val, 'f', -1, 64), - Unit: units.CPUUnitStr(suffix).GetCPUUnit(), - ProfilePlatformMapping: &repository.ProfilePlatformMapping{ - Platform: bean.RUNNER_PLATFORM, - }, - }, nil -} -func LoadCiReqMem(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { - val, suffix, err := units.ParseValAndUnit(infraConfig.CiReqMem) - if err != nil { - return nil, err + for _, infraConfiguration := range infraConfigurations { + if profilePlatformMappingId, ok := platformMappingId[infraConfiguration.UniqueId]; ok { + infraConfiguration.ProfilePlatformMappingId = profilePlatformMappingId + if infraConfiguration.ProfilePlatformMapping != nil { + infraConfiguration.ProfilePlatformMapping.Id = profilePlatformMappingId + } + } } - - return &repository.InfraProfileConfigurationEntity{ - Key: bean.MemoryRequestKey, - ValueString: strconv.FormatFloat(val, 'f', -1, 64), - Unit: units.MemoryUnitStr(suffix).GetMemoryUnit(), - ProfilePlatformMapping: &repository.ProfilePlatformMapping{ - Platform: bean.RUNNER_PLATFORM, - }, - }, nil + return infraConfigurations } -func LoadDefaultTimeout(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { - return &repository.InfraProfileConfigurationEntity{ - Key: bean.TimeOutKey, - ValueString: strconv.FormatInt(infraConfig.CiDefaultTimeout, 10), - Unit: units.SecondStr.GetTimeUnit(), - ProfilePlatformMapping: &repository.ProfilePlatformMapping{ - Platform: bean.RUNNER_PLATFORM, - }, - }, nil -} -func LoadInfraConfigInEntities(infraConfig *bean.InfraConfig, nodeSelectorLabel []string, taintKey, taintValue string) ([]*repository.InfraProfileConfigurationEntity, error) { - cpuLimit, err := LoadCiLimitCpu(infraConfig) - if err != nil { - return nil, err - } - memLimit, err := LoadCiLimitMem(infraConfig) - if err != nil { - return nil, err - } - cpuReq, err := LoadCiReqCpu(infraConfig) - if err != nil { - return nil, err - } - memReq, err := LoadCiReqMem(infraConfig) - if err != nil { - return nil, err - } - timeout, err := LoadDefaultTimeout(infraConfig) - if err != nil { - return nil, err +func GetGenericConfigurationBean[T any](configurationBean *v1.ConfigurationBean, typedValue T) *v1.GenericConfigurationBean[T] { + return &v1.GenericConfigurationBean[T]{ + ConfigurationBeanAbstract: configurationBean.ConfigurationBeanAbstract, + Value: typedValue, } - defaultConfigurations := []*repository.InfraProfileConfigurationEntity{cpuLimit, memLimit, cpuReq, memReq, timeout} - return defaultConfigurations, nil } -func setProfilePlatformMappingId(defaultProfile *bean.ProfileBeanDto, infraConfiguration *repository.InfraProfileConfigurationEntity) { - runnerPlatformConfig := defaultProfile.Configurations[bean.RUNNER_PLATFORM] - for _, runnerConfig := range runnerPlatformConfig { - if runnerConfig.Key == utils.GetConfigKeyStr(infraConfiguration.Key) { - //setting hte ppm id and Profile Id - infraConfiguration.ProfilePlatformMappingId = runnerConfig.ProfilePlatformMappingId +// FillMissingConfigurationsForThePayloadV0 - This function is used to fill the missing configurations in the payload +// after the k8sBuildXDriverOpts Migration => need for handling the updated of default / global profile +func FillMissingConfigurationsForThePayloadV0(profileToUpdate *v1.ProfileBeanDto, platformMapConfigs map[string][]*v1.ConfigurationBean) { + for platform, configBeans := range platformMapConfigs { + if existingConfig, exists := profileToUpdate.GetConfigurations()[platform]; exists { + // If the platform already exists in the payloadConfig, update missing NodeSelectors and TolerationsKey + defaultKeys := util.GetDefaultConfigKeysMapV0() + for _, beans := range existingConfig { + defaultKeys[beans.Key] = false + } + + for _, configBean := range configBeans { + // Add missing in case of NodeSelectors and TolerationsKey only + if (configBean.Key == v1.NODE_SELECTOR || configBean.Key == v1.TOLERATIONS) && defaultKeys[configBean.Key] { + profileToUpdate.GetConfigurations()[platform] = append(profileToUpdate.GetConfigurations()[platform], configBean) + } + } + } else { + // If the platform do not found in the update request, add all its configurations corresponding to its platform + profileToUpdate.GetConfigurations()[platform] = configBeans } } } diff --git a/pkg/infraConfig/adapter/audit/adapter.go b/pkg/infraConfig/adapter/audit/adapter.go new file mode 100644 index 0000000000..79c67af7e8 --- /dev/null +++ b/pkg/infraConfig/adapter/audit/adapter.go @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package audit + +import ( + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository/audit" + "strconv" +) + +func GetInfraConfigTriggerAudit(config *v1.InfraConfig) ([]*audit.InfraConfigTriggerHistory, error) { + infraConfigTriggerHistories := make([]*audit.InfraConfigTriggerHistory, 0) + infraConfigTriggerHistories = append(infraConfigTriggerHistories, GetCpuLimit(config)) + infraConfigTriggerHistories = append(infraConfigTriggerHistories, GetCpuRequest(config)) + infraConfigTriggerHistories = append(infraConfigTriggerHistories, GetMemoryLimit(config)) + infraConfigTriggerHistories = append(infraConfigTriggerHistories, GetMemoryRequest(config)) + infraConfigTriggerHistories = append(infraConfigTriggerHistories, GetCiDefaultTimeout(config)) + infraConfigEntTriggerHistories, err := getInfraConfigEntTriggerAudit(config) + if err != nil { + return infraConfigTriggerHistories, err + } + infraConfigTriggerHistories = append(infraConfigTriggerHistories, infraConfigEntTriggerHistories...) + return infraConfigTriggerHistories, nil +} + +func GetCpuLimit(config *v1.InfraConfig) *audit.InfraConfigTriggerHistory { + return &audit.InfraConfigTriggerHistory{ + ValueString: config.CiLimitCpu, + Key: v1.CPULimitKey, + } +} + +func GetCpuRequest(config *v1.InfraConfig) *audit.InfraConfigTriggerHistory { + return &audit.InfraConfigTriggerHistory{ + ValueString: config.CiReqCpu, + Key: v1.CPURequestKey, + } +} + +func GetMemoryLimit(config *v1.InfraConfig) *audit.InfraConfigTriggerHistory { + return &audit.InfraConfigTriggerHistory{ + ValueString: config.CiLimitMem, + Key: v1.MemoryLimitKey, + } +} + +func GetMemoryRequest(config *v1.InfraConfig) *audit.InfraConfigTriggerHistory { + return &audit.InfraConfigTriggerHistory{ + ValueString: config.CiReqMem, + Key: v1.MemoryRequestKey, + } +} + +func GetCiDefaultTimeout(config *v1.InfraConfig) *audit.InfraConfigTriggerHistory { + return &audit.InfraConfigTriggerHistory{ + ValueString: strconv.FormatFloat(config.CiDefaultTimeout, 'f', -1, 64), + Key: v1.TimeOutKey, + } +} diff --git a/client/argocdServer/connection/Config.go b/pkg/infraConfig/adapter/audit/adapter_ent.go similarity index 60% rename from client/argocdServer/connection/Config.go rename to pkg/infraConfig/adapter/audit/adapter_ent.go index 982694c19b..fd7d04f257 100644 --- a/client/argocdServer/connection/Config.go +++ b/pkg/infraConfig/adapter/audit/adapter_ent.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2024. Devtron Inc. + * Copyright (c) 2024. Devtron Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +14,13 @@ * limitations under the License. */ -package connection +package audit import ( - "github.com/caarlos0/env" + v1 "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository/audit" ) -type Config struct { - Host string `env:"CD_HOST" envDefault:"localhost"` - Port string `env:"CD_PORT" envDefault:"8000"` - Namespace string `env:"CD_NAMESPACE" envDefault:"devtroncd"` -} - -func GetConfig() (*Config, error) { - cfg := &Config{} - err := env.Parse(cfg) - return cfg, err +func getInfraConfigEntTriggerAudit(config *v1.InfraConfig) ([]*audit.InfraConfigTriggerHistory, error) { + return make([]*audit.InfraConfigTriggerHistory, 0), nil } diff --git a/pkg/infraConfig/bean/bean.go b/pkg/infraConfig/bean/bean.go deleted file mode 100644 index 476b4b3e7f..0000000000 --- a/pkg/infraConfig/bean/bean.go +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bean - -import ( - "github.com/devtron-labs/devtron/pkg/infraConfig/units" - "time" -) - -// service layer structs - -type ProfileBeanAbstract struct { - Id int `json:"id"` - Name string `json:"name" validate:"required,min=1,max=50"` - Description string `json:"description" validate:"max=350"` - BuildxDriverType BuildxDriver `json:"buildxDriverType" default:"kubernetes"` - Active bool `json:"active"` - Type ProfileType `json:"type"` - AppCount int `json:"appCount"` - CreatedBy int32 `json:"createdBy"` - CreatedOn time.Time `json:"createdOn"` - UpdatedBy int32 `json:"updatedBy"` - UpdatedOn time.Time `json:"updatedOn"` -} - -type BuildxDriver string - -func (b BuildxDriver) String() string { - return string(b) -} - -func (b BuildxDriver) IsKubernetes() bool { - return b == BuildxK8sDriver -} - -func (b BuildxDriver) IsDockerContainer() bool { - return b == BuildxDockerContainerDriver -} - -func (b BuildxDriver) IsPlatformSupported(platform string) bool { - return platform == RUNNER_PLATFORM -} - -func (b BuildxDriver) IsValid() bool { - return b.IsKubernetes() || b.IsDockerContainer() -} - -const ( - // BuildxK8sDriver is the default driver for buildx - BuildxK8sDriver BuildxDriver = "kubernetes" - // BuildxDockerContainerDriver is the driver for docker container - BuildxDockerContainerDriver BuildxDriver = "docker-container" -) - -const BuildxK8sDriverMigrated string = "build-infra-migrated" - -type ProfileBeanDto struct { - ProfileBeanAbstract - Configurations map[string][]*ConfigurationBean `json:"configurations"` -} - -// Deprecated -type ProfileBeanV0 struct { - ProfileBeanAbstract - Configurations []ConfigurationBeanV0 `json:"configurations" validate:"dive"` -} - -type ConfigurationBean struct { - ConfigurationBeanAbstract - Value interface{} `json:"value"` -} - -// Deprecated -type ConfigurationBeanV0 struct { - ConfigurationBeanAbstract - Value float64 `json:"value" validate:"required,gt=0"` -} - -type InfraConfigMetaData struct { - DefaultConfigurations map[string][]*ConfigurationBean `json:"defaultConfigurations"` - ConfigurationUnits map[ConfigKeyStr]map[string]units.Unit `json:"configurationUnits"` -} - -// Deprecated -type InfraConfigMetaDataV0 struct { - DefaultConfigurations []ConfigurationBeanV0 `json:"defaultConfigurations"` - ConfigurationUnits map[ConfigKeyStr]map[string]units.Unit `json:"configurationUnits"` -} - -type ProfileResponse struct { - Profile ProfileBeanDto `json:"profile"` - InfraConfigMetaData -} - -// Deprecated -type ProfileResponseV0 struct { - Profile ProfileBeanV0 `json:"profile"` - InfraConfigMetaDataV0 -} - -type Scope struct { - AppId int -} - -type ConfigurationBeanAbstract struct { - Id int `json:"id"` - Key ConfigKeyStr `json:"key"` - Unit string `json:"unit"` - ProfilePlatformMappingId int `json:"profilePlatformMappingId"` - Active bool `json:"active"` - ProfileName string `json:"profileName"` - ProfileId int `json:"profileId"` -} - -// InfraConfig is used for read only purpose outside this package -type InfraConfig struct { - // currently only for ci - CiLimitCpu string `env:"LIMIT_CI_CPU" envDefault:"0.5"` - CiLimitMem string `env:"LIMIT_CI_MEM" envDefault:"3G"` - CiReqCpu string `env:"REQ_CI_CPU" envDefault:"0.5"` - CiReqMem string `env:"REQ_CI_MEM" envDefault:"3G"` - CiDefaultTimeout int64 `env:"DEFAULT_TIMEOUT" envDefault:"3600"` -} - -func (infraConfig InfraConfig) GetCiLimitCpu() string { - return infraConfig.CiLimitCpu -} - -func (infraConfig *InfraConfig) SetCiLimitCpu(cpu string) { - infraConfig.CiLimitCpu = cpu -} - -func (infraConfig InfraConfig) GetCiLimitMem() string { - return infraConfig.CiLimitMem -} - -func (infraConfig *InfraConfig) SetCiLimitMem(mem string) { - infraConfig.CiLimitMem = mem -} - -func (infraConfig InfraConfig) GetCiReqCpu() string { - return infraConfig.CiReqCpu -} - -func (infraConfig *InfraConfig) SetCiReqCpu(cpu string) { - infraConfig.CiReqCpu = cpu -} - -func (infraConfig InfraConfig) GetCiReqMem() string { - return infraConfig.CiReqMem -} - -func (infraConfig *InfraConfig) SetCiReqMem(mem string) { - infraConfig.CiReqMem = mem -} - -func (infraConfig InfraConfig) GetCiDefaultTimeout() int64 { - return infraConfig.CiDefaultTimeout -} - -func (infraConfig *InfraConfig) SetCiDefaultTimeout(timeout int64) { - infraConfig.CiDefaultTimeout = timeout -} - -type ProfileAndConfig struct { - GlobalProfile *ProfileBeanDto `json:"-"` - AppliedProfile *ProfileBeanDto `json:"-"` - Platforms []string `json:"-"` -} diff --git a/pkg/infraConfig/bean/constants.go b/pkg/infraConfig/bean/constants.go deleted file mode 100644 index 99b5227fa7..0000000000 --- a/pkg/infraConfig/bean/constants.go +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bean - -type ConfigKey int -type ConfigKeyStr string -type ProfileType string - -const NORMAL ProfileType = "NORMAL" -const InvalidUnit = "invalid %s unit found in %s " -const InvalidTypeValue = "invalid value found in %s with value %s " -const GLOBAL_PROFILE_NAME = "global" - -// TODO Asutosh: Backward compatibility for default profile is compromised. revisit this. -const DEFAULT_PROFILE_NAME = "default" -const DEFAULT_PROFILE_EXISTS = "default profile exists" -const NO_PROPERTIES_FOUND = "no properties found" -const DEFAULT ProfileType = "DEFAULT" -const GLOBAL ProfileType = "GLOBAL" -const InvalidProfileName = "profile name is invalid" -const PayloadValidationError = "payload validation failed" -const CPULimReqErrorCompErr = "cpu limit should not be less than cpu request" -const MEMLimReqErrorCompErr = "memory limit should not be less than memory request" -const InvalidValueType = "invalid Value type Found" - -const CPULimitKey ConfigKey = 1 -const CPURequestKey ConfigKey = 2 -const MemoryLimitKey ConfigKey = 3 -const MemoryRequestKey ConfigKey = 4 -const TimeOutKey ConfigKey = 5 - -// whenever new constant gets added here , -// we need to add it in GetDefaultConfigKeysMap method as well - -const CPU_LIMIT ConfigKeyStr = "cpu_limit" -const CPU_REQUEST ConfigKeyStr = "cpu_request" -const MEMORY_LIMIT ConfigKeyStr = "memory_limit" -const MEMORY_REQUEST ConfigKeyStr = "memory_request" -const TIME_OUT ConfigKeyStr = "timeout" - -// internal-platforms -const RUNNER_PLATFORM = "runner" -const QualifiedProfileMaxLength = 253 -const QualifiedDescriptionMaxLength = 350 -const QualifiedPlatformMaxLength = 50 -const ConfigurationMissingInGlobalPlatform = "configuration missing in the global Platform" diff --git a/pkg/infraConfig/bean/v0/configurationsV0.go b/pkg/infraConfig/bean/v0/configurationsV0.go new file mode 100644 index 0000000000..83bb5a4458 --- /dev/null +++ b/pkg/infraConfig/bean/v0/configurationsV0.go @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v0 implements the infra config with float64 values only. +// +// Deprecated: v0 is functionally broken and should not be used +// except for compatibility with legacy systems. Use v1 instead. +// +// This package is frozen and no new functionality will be added. +package v0 + +import ( + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" +) + +// Deprecated: ConfigurationBeanV0 is deprecated in favor of v1.ConfigurationBean +type ConfigurationBeanV0 struct { + v1.ConfigurationBeanAbstract + Value float64 `json:"value" validate:"required,gt=0"` +} diff --git a/pkg/infraConfig/bean/v0/profileV0.go b/pkg/infraConfig/bean/v0/profileV0.go new file mode 100644 index 0000000000..58937bc769 --- /dev/null +++ b/pkg/infraConfig/bean/v0/profileV0.go @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v0 implements the infra config with float64 values only. +// +// Deprecated: v0 is functionally broken and should not be used +// except for compatibility with legacy systems. Use v1 instead. +// +// This package is frozen and no new functionality will be added. +package v0 + +import ( + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" +) + +// Deprecated: ProfileBeanV0 is deprecated in favor of v1.ProfileBeanDto +type ProfileBeanV0 struct { + v1.ProfileBeanAbstract + Configurations []ConfigurationBeanV0 `json:"configurations" validate:"dive"` +} + +func (profileBean *ProfileBeanV0) GetBuildxDriverType() v1.BuildxDriver { + if profileBean == nil { + return "" + } + return profileBean.ProfileBeanAbstract.GetBuildxDriverType() +} + +func (profileBean *ProfileBeanV0) GetDescription() string { + if profileBean == nil { + return "" + } + return profileBean.ProfileBeanAbstract.GetDescription() +} + +func (profileBean *ProfileBeanV0) GetName() string { + if profileBean == nil { + return "" + } + return profileBean.ProfileBeanAbstract.GetName() +} + +// Deprecated: ProfileResponseV0 is deprecated in favor of v1.ProfileResponse +type ProfileResponseV0 struct { + Profile ProfileBeanV0 `json:"profile"` + InfraConfigMetaDataV0 +} + +// Deprecated: InfraConfigMetaDataV0 is deprecated in favor of v1.InfraConfigMetaData +type InfraConfigMetaDataV0 struct { + DefaultConfigurations []ConfigurationBeanV0 `json:"defaultConfigurations"` + ConfigurationUnits map[v1.ConfigKeyStr]map[string]v1.Unit `json:"configurationUnits"` +} diff --git a/pkg/infraConfig/bean/v1/bean.go b/pkg/infraConfig/bean/v1/bean.go new file mode 100644 index 0000000000..5f28b72436 --- /dev/null +++ b/pkg/infraConfig/bean/v1/bean.go @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 implements the infra config with interface values. +package v1 + +// BuildxK8sDriverMigrated is the marker flag to check if the infra config is migrated completely. +const BuildxK8sDriverMigrated string = "build-infra-migrated" + +// Scope refers to the identifier scope for the infra config +// - Currently, the infra config profile is applied to a specific app only. +type Scope struct { + AppId int +} + +type ConfigKeyPlatformKey struct { + Key ConfigKey + Platform string +} diff --git a/pkg/infraConfig/bean/v1/configurations.go b/pkg/infraConfig/bean/v1/configurations.go new file mode 100644 index 0000000000..77fb51a287 --- /dev/null +++ b/pkg/infraConfig/bean/v1/configurations.go @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 implements the infra config with interface values. +package v1 + +type ConfigurationBean struct { + ConfigurationBeanAbstract + Value any `json:"value,omitempty"` + Count int `json:"count,omitempty"` + ConfigState ConfigStateType `json:"configState,omitempty"` + AppliedConfigIds []int `json:"-"` +} + +func (c *ConfigurationBean) DeepCopy() *ConfigurationBean { + if c == nil { + return nil + } + config := *c + return &config +} + +func (c *ConfigurationBean) IsEmpty() bool { + return c == nil +} + +func (c *ConfigurationBean) GetStringValue() string { + return c.Value.(string) +} + +// ConfigStateType represents the derived state of the ConfigurationBean.Value +type ConfigStateType string + +const ( + // OVERRIDDEN is used when the configuration is overridden in the profile + OVERRIDDEN ConfigStateType = "OVERRIDDEN" + // PARTIALLY_INHERITING is used when the configuration is partially inherited from the global profile + PARTIALLY_INHERITING ConfigStateType = "PARTIALLY_INHERITING" + // INHERITING_GLOBAL_PROFILE is used when the configuration is inherited from the global profile + INHERITING_GLOBAL_PROFILE ConfigStateType = "INHERITING_GLOBAL_PROFILE" +) + +// GenericConfigurationBean is for internal use only +// - used for specific handling of configurations and to avoid type assertion +// - not exposed to the API +// - derived from ConfigurationBean +type GenericConfigurationBean[T any] struct { + ConfigurationBeanAbstract + Value T +} + +type ConfigurationBeanAbstract struct { + Id int `json:"id"` + Key ConfigKeyStr `json:"key" validate:"required,oneof=cpu_limit cpu_request memory_limit memory_request timeout node_selector tolerations cm cs"` + Unit string `json:"unit"` + ProfileName string `json:"profileName,omitempty"` + ProfileId int `json:"profileId,omitempty"` + Active bool `json:"active"` +} + +// whenever new constant gets added here, +// we need to add it in util.GetConfigKeysMapForPlatform method as well + +// ConfigKey represents the configuration key in the DB model +type ConfigKey int + +const ( + CPULimitKey ConfigKey = 1 + CPURequestKey ConfigKey = 2 + MemoryLimitKey ConfigKey = 3 + MemoryRequestKey ConfigKey = 4 + TimeOutKey ConfigKey = 5 + + // enterprise-only keys; kept together to maintain order + + NodeSelectorKey ConfigKey = 6 + TolerationsKey ConfigKey = 7 + ConfigMapKey ConfigKey = 8 + SecretKey ConfigKey = 9 +) + +// ConfigKeyStr represents the configuration key in the API +type ConfigKeyStr string + +const ( + CPU_LIMIT ConfigKeyStr = "cpu_limit" + CPU_REQUEST ConfigKeyStr = "cpu_request" + MEMORY_LIMIT ConfigKeyStr = "memory_limit" + MEMORY_REQUEST ConfigKeyStr = "memory_request" + TIME_OUT ConfigKeyStr = "timeout" + + // enterprise-only keys; kept together to maintain order + + NODE_SELECTOR ConfigKeyStr = "node_selector" + TOLERATIONS ConfigKeyStr = "tolerations" + CONFIG_MAP ConfigKeyStr = "cm" + SECRET ConfigKeyStr = "cs" +) + +// AllConfigKeysV0 contains the list of supported configuration keys in V0 +var AllConfigKeysV0 = []ConfigKeyStr{CPU_LIMIT, CPU_REQUEST, MEMORY_LIMIT, MEMORY_REQUEST, TIME_OUT} + +// AllConfigKeysV1 contains the list of supported configuration keys in V1 +var AllConfigKeysV1 = append(AllConfigKeysV0, []ConfigKeyStr{NODE_SELECTOR, TOLERATIONS, CONFIG_MAP, SECRET}...) + +type InfraConfigKeys map[ConfigKeyStr]bool + +func (s InfraConfigKeys) IsSupported(key ConfigKeyStr) bool { + if s == nil { + return false + } + _, ok := s[key] + return ok +} + +func (s InfraConfigKeys) IsConfigured(key ConfigKeyStr) bool { + return s.IsSupported(key) && !s[key] +} + +func (s InfraConfigKeys) GetAllSupportedKeys() []ConfigKeyStr { + keys := make([]ConfigKeyStr, 0) + for key := range s { + if s.IsSupported(key) { + keys = append(keys, key) + } + } + return keys +} + +func (s InfraConfigKeys) GetUnConfiguredKeys() []ConfigKeyStr { + keys := make([]ConfigKeyStr, 0) + for key := range s { + if !s.IsSupported(key) { + continue + } + if !s.IsConfigured(key) { + keys = append(keys, key) + } + } + return keys +} + +func (s InfraConfigKeys) MarkUnConfigured(key ConfigKeyStr) InfraConfigKeys { + if s.IsSupported(key) { + s[key] = true + } + return s +} + +func (s InfraConfigKeys) MarkConfigured(key ConfigKeyStr) InfraConfigKeys { + if s.IsSupported(key) { + s[key] = false + } + return s +} diff --git a/pkg/infraConfig/bean/v1/constants.go b/pkg/infraConfig/bean/v1/constants.go new file mode 100644 index 0000000000..4722b5ab4d --- /dev/null +++ b/pkg/infraConfig/bean/v1/constants.go @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 implements the infra config with interface values. +package v1 + +const GLOBAL_PROFILE_NAME = "global" + +const DEFAULT_PROFILE_NAME = "default" + +// QualifiedProfileMaxLength is the maximum length of an infra profile name +const QualifiedProfileMaxLength int = 50 + +// QualifiedDescriptionMaxLength is the maximum length of an infra profile description +const QualifiedDescriptionMaxLength int = 350 diff --git a/pkg/infraConfig/bean/v1/infra_config.go b/pkg/infraConfig/bean/v1/infra_config.go new file mode 100644 index 0000000000..3f57e57fae --- /dev/null +++ b/pkg/infraConfig/bean/v1/infra_config.go @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 implements the infra config with interface values. +package v1 + +import ( + "github.com/devtron-labs/devtron/api/bean" + "math" +) + +// InfraConfig is used for read-only purpose outside this package +type InfraConfig struct { + // currently only for ci + CiLimitCpu string `env:"LIMIT_CI_CPU" envDefault:"0.5"` + CiLimitMem string `env:"LIMIT_CI_MEM" envDefault:"3G"` + CiReqCpu string `env:"REQ_CI_CPU" envDefault:"0.5"` + CiReqMem string `env:"REQ_CI_MEM" envDefault:"3G"` + // CiDefaultTimeout is the default timeout for CI jobs in seconds + // Earlier it was in int64, but now it is in float64 + CiDefaultTimeout float64 `env:"DEFAULT_TIMEOUT" envDefault:"3600"` + + // cm and cs + ConfigMaps []bean.ConfigSecretMap `env:"-"` + Secrets []bean.ConfigSecretMap `env:"-"` + InfraConfigEnt +} + +func (infraConfig *InfraConfig) GetCiLimitCpu() string { + if infraConfig == nil { + return "" + } + return infraConfig.CiLimitCpu +} + +func (infraConfig *InfraConfig) SetCiLimitCpu(cpu string) *InfraConfig { + if infraConfig == nil { + return nil + } + infraConfig.CiLimitCpu = cpu + return infraConfig +} + +func (infraConfig *InfraConfig) GetCiLimitMem() string { + if infraConfig == nil { + return "" + } + return infraConfig.CiLimitMem +} + +func (infraConfig *InfraConfig) SetCiLimitMem(mem string) *InfraConfig { + if infraConfig == nil { + return nil + } + infraConfig.CiLimitMem = mem + return infraConfig +} + +func (infraConfig *InfraConfig) GetCiReqCpu() string { + if infraConfig == nil { + return "" + } + return infraConfig.CiReqCpu +} + +func (infraConfig *InfraConfig) SetCiReqCpu(cpu string) *InfraConfig { + if infraConfig == nil { + return nil + } + infraConfig.CiReqCpu = cpu + return infraConfig +} + +func (infraConfig *InfraConfig) GetCiReqMem() string { + if infraConfig == nil { + return "" + } + return infraConfig.CiReqMem +} + +func (infraConfig *InfraConfig) SetCiReqMem(mem string) *InfraConfig { + if infraConfig == nil { + return nil + } + infraConfig.CiReqMem = mem + return infraConfig +} + +func (infraConfig *InfraConfig) GetCiDefaultTimeout() float64 { + if infraConfig == nil { + return 0 + } + return infraConfig.CiDefaultTimeout +} + +func (infraConfig *InfraConfig) GetCiTimeoutInt() int64 { + if infraConfig == nil { + return 0 + } + modifiedValue := math.Min(math.Floor(infraConfig.CiDefaultTimeout), math.MaxInt64) + return int64(modifiedValue) +} + +func (infraConfig *InfraConfig) SetCiTimeout(timeout float64) *InfraConfig { + if infraConfig == nil { + return nil + } + infraConfig.CiDefaultTimeout = timeout + return infraConfig +} diff --git a/pkg/infraConfig/bean/v1/infra_config_ent.go b/pkg/infraConfig/bean/v1/infra_config_ent.go new file mode 100644 index 0000000000..c3c9d4079f --- /dev/null +++ b/pkg/infraConfig/bean/v1/infra_config_ent.go @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +type InfraConfigEnt struct { +} + +func (infraConfig *InfraConfig) SetCiVariableSnapshot(value map[string]string) *InfraConfig { + return infraConfig +} diff --git a/pkg/infraConfig/bean/v1/platforms.go b/pkg/infraConfig/bean/v1/platforms.go new file mode 100644 index 0000000000..744a265ed8 --- /dev/null +++ b/pkg/infraConfig/bean/v1/platforms.go @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 implements the infra config with interface values. +package v1 + +type PlatformResponse struct { + Platforms []string `json:"platforms"` +} + +// internal-platforms +const ( + // RUNNER_PLATFORM is the name of the default platform; a reserved name + RUNNER_PLATFORM = "runner" + + // Deprecated: use RUNNER_PLATFORM instead + // CI_RUNNER_PLATFORM is earlier used as the name of the default platform + CI_RUNNER_PLATFORM = "ci-runner" +) diff --git a/pkg/infraConfig/bean/v1/profile.go b/pkg/infraConfig/bean/v1/profile.go new file mode 100644 index 0000000000..97c5d2e983 --- /dev/null +++ b/pkg/infraConfig/bean/v1/profile.go @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 implements the infra config with interface values. +package v1 + +import "strings" + +type ProfileBeanDto struct { + ProfileBeanAbstract + Configurations map[string][]*ConfigurationBean `json:"configurations"` +} + +func (profileBean *ProfileBeanDto) GetDescription() string { + if profileBean == nil { + return "" + } + return profileBean.ProfileBeanAbstract.GetDescription() +} + +func (profileBean *ProfileBeanDto) GetName() string { + if profileBean == nil { + return "" + } + return profileBean.ProfileBeanAbstract.GetName() +} + +func (profileBean *ProfileBeanDto) DeepCopy() *ProfileBeanDto { + if profileBean == nil { + return nil + } + profile := *profileBean + configurations := make(map[string][]*ConfigurationBean) + for key, value := range profileBean.Configurations { + configurations[key] = value + } + profile.Configurations = configurations + return &profile +} + +func (profileBean *ProfileBeanDto) GetConfigurations() map[string][]*ConfigurationBean { + configurations := make(map[string][]*ConfigurationBean) + if profileBean == nil || len(profileBean.Configurations) == 0 { + return configurations + } + return profileBean.Configurations +} + +func (profileBean *ProfileBeanDto) SetPlatformConfigurations(platform string, configurations []*ConfigurationBean) *ProfileBeanDto { + if profileBean == nil { + return nil + } + if profileBean.Configurations == nil { + profileBean.Configurations = make(map[string][]*ConfigurationBean) + } + profileBean.Configurations[platform] = configurations + return profileBean +} + +type ProfileBeanAbstract struct { + Id int `json:"id"` + Name string `json:"name" validate:"required,min=1,max=50,global-entity-name"` + Description string `json:"description" validate:"max=350"` + Active bool `json:"active"` + Type ProfileType `json:"type"` + AppCount int `json:"appCount"` + ProfileBeanAbstractEnt +} + +func (p *ProfileBeanAbstract) GetDescription() string { + if p == nil { + return "" + } + return strings.TrimSpace(p.Description) +} + +func (p *ProfileBeanAbstract) GetName() string { + if p == nil { + return "" + } + return strings.TrimSpace(strings.ToLower(p.Name)) +} + +type ProfileType string + +const ( + GLOBAL ProfileType = "GLOBAL" + DEFAULT ProfileType = "DEFAULT" + NORMAL ProfileType = "NORMAL" +) + +type BuildxDriver string + +func (b BuildxDriver) String() string { + return string(b) +} + +func (b BuildxDriver) IsKubernetes() bool { + return b == BuildxK8sDriver +} + +func (b BuildxDriver) IsDockerContainer() bool { + return b == BuildxDockerContainerDriver +} + +func (b BuildxDriver) IsPlatformSupported(platform string) bool { + if b.IsKubernetes() { + // k8s supports all platforms + return true + } else { + // docker container supports only runner platform + return platform == RUNNER_PLATFORM + } +} + +func (b BuildxDriver) IsValid() bool { + return b.IsKubernetes() || b.IsDockerContainer() +} + +const ( + // BuildxK8sDriver is the default driver for buildx + BuildxK8sDriver BuildxDriver = "kubernetes" + // BuildxDockerContainerDriver is the driver for docker container + BuildxDockerContainerDriver BuildxDriver = "docker-container" +) + +type ProfileResponse struct { + Profile ProfileBeanDto `json:"profile"` + InfraConfigMetaData +} + +type InfraConfigMetaData struct { + DefaultConfigurations map[string][]*ConfigurationBean `json:"defaultConfigurations,omitempty"` + ConfigurationUnits map[ConfigKeyStr]map[string]Unit `json:"configurationUnits,omitempty"` +} diff --git a/pkg/infraConfig/bean/v1/profile_ent.go b/pkg/infraConfig/bean/v1/profile_ent.go new file mode 100644 index 0000000000..5d8615cb1e --- /dev/null +++ b/pkg/infraConfig/bean/v1/profile_ent.go @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 implements the infra config with interface values. +package v1 + +type ProfileBeanAbstractEnt struct { + BuildxDriverType BuildxDriver `json:"buildxDriverType" default:"kubernetes"` +} + +func (profileBean *ProfileBeanDto) GetBuildxDriverType() BuildxDriver { + return BuildxDockerContainerDriver +} + +func (p *ProfileBeanAbstract) GetBuildxDriverType() BuildxDriver { + return BuildxDockerContainerDriver +} diff --git a/pkg/infraConfig/bean/v1/unit.go b/pkg/infraConfig/bean/v1/unit.go new file mode 100644 index 0000000000..a9cb7d3715 --- /dev/null +++ b/pkg/infraConfig/bean/v1/unit.go @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 implements the infra config with interface values. +package v1 + +// Unit represents unitType of a configuration +type Unit struct { + // Name is unitType name + Name string `json:"name"` + // ConversionFactor is used to convert this unitType to the base unitType + // if ConversionFactor is 1, then this is the base unitType + ConversionFactor float64 `json:"conversionFactor"` +} diff --git a/pkg/infraConfig/config/infraConfigClient.go b/pkg/infraConfig/config/infraConfigClient.go new file mode 100644 index 0000000000..c52400eb2c --- /dev/null +++ b/pkg/infraConfig/config/infraConfigClient.go @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "fmt" + globalUtil "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/config/read" + "github.com/devtron-labs/devtron/pkg/infraConfig/adapter" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/devtron-labs/devtron/pkg/infraConfig/util" + "github.com/devtron-labs/devtron/pkg/variables" + "github.com/devtron-labs/devtron/util/sliceUtil" + "github.com/go-pg/pg" + "go.uber.org/zap" + "net/http" + "strconv" +) + +type InfraConfigClient interface { + GetDefaultConfigurationForPlatform(platformName string, defaultConfigurationsMap map[string][]*v1.ConfigurationBean) []*v1.ConfigurationBean + GetConfigurationBeansForProfile(infraProfileConfigurationEntities []*repository.InfraProfileConfigurationEntity, profileName string) (map[string][]*v1.ConfigurationBean, error) + Validate(profileBean, defaultProfile *v1.ProfileBeanDto) (map[string]v1.InfraConfigKeys, error) + GetConfigurationUnits() (map[v1.ConfigKeyStr]map[string]v1.Unit, error) + GetInfraProfileConfigurationEntities(profileBean *v1.ProfileBeanDto, userId int32) ([]*repository.InfraProfileConfigurationEntity, error) + HandlePostUpdateOperations(tx *pg.Tx, updatedInfraConfigs []*repository.InfraProfileConfigurationEntity) error + HandlePostCreateOperations(tx *pg.Tx, createdInfraConfigs []*repository.InfraProfileConfigurationEntity) error + GetInfraConfigEntities(profileId int, infraConfig *v1.InfraConfig) ([]*repository.InfraProfileConfigurationEntity, error) + OverrideInfraConfig(infraConfiguration *v1.InfraConfig, configurationBean *v1.ConfigurationBean) (*v1.InfraConfig, error) + ConvertToProfilePlatformMap(infraProfileConfigurationEntities []*repository.InfraProfileConfigurationEntity, profilesMap map[int]*v1.ProfileBeanDto, profilePlatforms []*repository.ProfilePlatformMapping) (map[int]map[string][]*v1.ConfigurationBean, error) + MergeInfraConfigurations(supportedConfigKey v1.ConfigKeyStr, profileConfiguration *v1.ConfigurationBean, defaultConfigurations []*v1.ConfigurationBean) (*v1.ConfigurationBean, error) + HandleInfraConfigTriggerAudit(workflowId int, triggeredBy int32, infraConfigs map[string]*v1.InfraConfig) error + InfraConfigEntClient +} + +type InfraConfigClientImpl struct { + logger *zap.SugaredLogger + configFactories *configFactories + unitFactoryMap *unitFactories +} + +func NewInfraConfigClient(logger *zap.SugaredLogger, + scopedVariableManager variables.ScopedVariableManager, + configReadService read.ConfigReadService) *InfraConfigClientImpl { + return &InfraConfigClientImpl{ + logger: logger, + configFactories: getConfigFactory(logger, scopedVariableManager, configReadService), + unitFactoryMap: getUnitFactoryMap(logger), + } +} + +func (impl *InfraConfigClientImpl) getCPUConfigFactory() configFactory[float64] { + return impl.configFactories.cpuConfigFactory +} + +func (impl *InfraConfigClientImpl) getMemoryConfigFactory() configFactory[float64] { + return impl.configFactories.memConfigFactory +} + +func (impl *InfraConfigClientImpl) getTimeoutConfigFactory() configFactory[float64] { + return impl.configFactories.timeoutConfigFactory +} + +func (impl *InfraConfigClientImpl) GetDefaultConfigurationForPlatform(platformName string, defaultConfigurationsMap map[string][]*v1.ConfigurationBean) []*v1.ConfigurationBean { + if len(defaultConfigurationsMap) == 0 { + return []*v1.ConfigurationBean{} + } + // Check if the platform exists in the defaultConfigurationsMap + defaultConfigurations, exists := defaultConfigurationsMap[platformName] + if !exists { + // If not, fallback to the default platform configurations + return filterSupportedConfigurations(platformName, defaultConfigurationsMap[v1.RUNNER_PLATFORM]) + } + return filterSupportedConfigurations(platformName, defaultConfigurations) +} + +func (impl *InfraConfigClientImpl) GetConfigurationBeansForProfile(infraProfileConfigurationEntities []*repository.InfraProfileConfigurationEntity, profileName string) (map[string][]*v1.ConfigurationBean, error) { + platformMap := make(map[string][]*v1.ConfigurationBean) + if len(infraProfileConfigurationEntities) == 0 { + return platformMap, nil + } + if profileName == "" { + errMsg := "profileName cannot be empty" + return platformMap, globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + for _, infraProfileConfiguration := range infraProfileConfigurationEntities { + if infraProfileConfiguration == nil { + continue + } + configurationBean, err := impl.getConfigurationBean(infraProfileConfiguration, profileName) + if err != nil { + impl.logger.Errorw("failed to get configurations for profile", "err", err, "profileName", profileName) + errMsg := fmt.Sprintf("failed to get configurations for profile '%s'", profileName) + return platformMap, globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + platform := infraProfileConfiguration.ProfilePlatformMapping.Platform + if len(platform) == 0 { + platform = v1.RUNNER_PLATFORM + } + // Add the ConfigurationBean to the corresponding platform entry in the map + platformMap[platform] = append(platformMap[platform], configurationBean) + } + return platformMap, nil +} + +func (impl *InfraConfigClientImpl) Validate(profileBean, defaultProfile *v1.ProfileBeanDto) (map[string]v1.InfraConfigKeys, error) { + platformWiseDefaultConfigKeyMap := make(map[string]v1.InfraConfigKeys) + for platformName, platformConfigurations := range profileBean.GetConfigurations() { + // Check if the same platform exists in global profile, + // if not exist, then take go falling on the default platform value + defaultConfigurations := impl.GetDefaultConfigurationForPlatform(platformName, defaultProfile.GetConfigurations()) + defaultConfigKeyMap, err := impl.validateConfig(platformName, platformConfigurations, defaultConfigurations, false) + if err != nil { + return platformWiseDefaultConfigKeyMap, err + } + platformWiseDefaultConfigKeyMap[platformName] = defaultConfigKeyMap + } + return platformWiseDefaultConfigKeyMap, nil +} + +func (impl *InfraConfigClientImpl) GetConfigurationUnits() (map[v1.ConfigKeyStr]map[string]v1.Unit, error) { + configurationUnits := make(map[v1.ConfigKeyStr]map[string]v1.Unit) + for configKey, supportedUnits := range impl.getCPUConfigFactory().getSupportedUnits() { + configurationUnits[configKey] = supportedUnits + } + for configKey, supportedUnits := range impl.getMemoryConfigFactory().getSupportedUnits() { + configurationUnits[configKey] = supportedUnits + } + for configKey, supportedUnits := range impl.getTimeoutConfigFactory().getSupportedUnits() { + configurationUnits[configKey] = supportedUnits + } + entConfigurationUnits, err := impl.getEntConfigurationUnits() + if err != nil { + return configurationUnits, err + } + for configKey, supportedUnits := range entConfigurationUnits { + configurationUnits[configKey] = supportedUnits + } + return configurationUnits, nil +} + +// GetInfraProfileConfigurationEntities converts bean.ProfileBeanDto back to []repository.InfraProfileConfigurationEntity +func (impl *InfraConfigClientImpl) GetInfraProfileConfigurationEntities(profileBean *v1.ProfileBeanDto, userId int32) ([]*repository.InfraProfileConfigurationEntity, error) { + var entities []*repository.InfraProfileConfigurationEntity + for platform, configBeans := range profileBean.GetConfigurations() { + for _, configBean := range configBeans { + configBean.ProfileId = profileBean.Id + configBean.ProfileName = profileBean.GetName() + valueString, err := impl.formatTypedValueAsString(configBean.Key, configBean.Value) + if err != nil { + return nil, err + } + entity := adapter.GetInfraProfileEntity(configBean, valueString, platform, userId) + entities = append(entities, entity) + } + } + return entities, nil +} + +func (impl *InfraConfigClientImpl) GetInfraConfigEntities(profileId int, infraConfig *v1.InfraConfig) ([]*repository.InfraProfileConfigurationEntity, error) { + defaultConfigurations := make([]*repository.InfraProfileConfigurationEntity, 0) + cpuInfraEntities, err := impl.getCPUConfigFactory().getInfraConfigEntities(infraConfig, profileId, v1.RUNNER_PLATFORM) + if err != nil { + impl.logger.Errorw("error in getting infra cpu config entities", "error", err, "infraConfig", infraConfig) + return defaultConfigurations, err + } + defaultConfigurations = sliceUtil.Filter(defaultConfigurations, cpuInfraEntities, + func(entity *repository.InfraProfileConfigurationEntity) bool { + return entity != nil + }) + memInfraEntities, err := impl.getMemoryConfigFactory().getInfraConfigEntities(infraConfig, profileId, v1.RUNNER_PLATFORM) + if err != nil { + impl.logger.Errorw("error in getting infra memory config entities", "error", err, "infraConfig", infraConfig) + return defaultConfigurations, err + } + defaultConfigurations = sliceUtil.Filter(defaultConfigurations, memInfraEntities, + func(entity *repository.InfraProfileConfigurationEntity) bool { + return entity != nil + }) + timeoutInfraEntities, err := impl.getTimeoutConfigFactory().getInfraConfigEntities(infraConfig, profileId, v1.RUNNER_PLATFORM) + if err != nil { + impl.logger.Errorw("error in getting infra timeout config entities", "error", err, "infraConfig", infraConfig) + return defaultConfigurations, err + } + defaultConfigurations = sliceUtil.Filter(defaultConfigurations, timeoutInfraEntities, + func(entity *repository.InfraProfileConfigurationEntity) bool { + return entity != nil + }) + entInfraEntities, err := impl.getInfraConfigEntEntities(profileId, infraConfig) + if err != nil { + impl.logger.Errorw("error in getting infra ent config entities", "error", err, "infraConfig", infraConfig) + return defaultConfigurations, err + } + defaultConfigurations = append(defaultConfigurations, entInfraEntities...) + return defaultConfigurations, nil +} + +func (impl *InfraConfigClientImpl) ConvertToProfilePlatformMap(infraProfileConfigurationEntities []*repository.InfraProfileConfigurationEntity, + profilesMap map[int]*v1.ProfileBeanDto, profilePlatforms []*repository.ProfilePlatformMapping) (map[int]map[string][]*v1.ConfigurationBean, error) { + // Create a map to track profileId and platform presence + profilePlatformTracker := make(map[int]map[string]bool) + + // Initialize the tracker with platforms from profilePlatforms + for _, profilePlatform := range profilePlatforms { + if _, exists := profilePlatformTracker[profilePlatform.ProfileId]; !exists { + profilePlatformTracker[profilePlatform.ProfileId] = make(map[string]bool) + } + profilePlatformTracker[profilePlatform.ProfileId][profilePlatform.Platform] = true + } + + profilePlatformMap := make(map[int]map[string][]*v1.ConfigurationBean) + + for _, infraProfileConfiguration := range infraProfileConfigurationEntities { + profileId := infraProfileConfiguration.ProfilePlatformMapping.ProfileId + profile, ok := profilesMap[profileId] + + if !ok || profile == nil { + continue + } + + // Initialize the inner map for the current ProfileId if it doesn't exist + if _, exists := profilePlatformMap[profileId]; !exists { + profilePlatformMap[profileId] = make(map[string][]*v1.ConfigurationBean) + } + + // Convert entity to ConfigurationBean + configurationBean, err := impl.getConfigurationBean(infraProfileConfiguration, profile.GetName()) + if err != nil { + impl.logger.Errorw("failed to get configurations for profile", "err", err, "profileName", profile.GetName()) + errMsg := fmt.Sprintf("failed to get configurations for profile '%s'", profile.GetName()) + return nil, globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + platform := infraProfileConfiguration.ProfilePlatformMapping.Platform + if len(platform) == 0 { + platform = v1.RUNNER_PLATFORM + } + + // Append the ConfigurationBean to the list under the appropriate platform in the inner map + profilePlatformMap[profileId][platform] = append( + profilePlatformMap[profileId][platform], + configurationBean, + ) + + // Mark the platform as processed + if platformTracker, exists := profilePlatformTracker[profileId]; exists { + platformTracker[platform] = false + } + } + // Ensure all platforms from profilePlatformTracker are included in the result map + for profileId, platforms := range profilePlatformTracker { + if _, exists := profilePlatformMap[profileId]; !exists { + profilePlatformMap[profileId] = make(map[string][]*v1.ConfigurationBean) + } + for platform, isMissing := range platforms { + if isMissing { + profilePlatformMap[profileId][platform] = []*v1.ConfigurationBean{} + } + } + } + return profilePlatformMap, nil +} + +func (impl *InfraConfigClientImpl) HandleInfraConfigTriggerAudit(workflowId int, triggeredBy int32, infraConfigs map[string]*v1.InfraConfig) error { + for platform, infraConfig := range infraConfigs { + supportedConfigKeys := util.GetConfigKeysMapForPlatform(platform) + err := impl.handleInfraConfigTriggerAudit(supportedConfigKeys, workflowId, triggeredBy, infraConfig) + if err != nil { + return err + } + } + return nil +} + +func (impl *InfraConfigClientImpl) validateConfig(platformName string, platformConfigurations, defaultConfigurations []*v1.ConfigurationBean, skipError bool) (v1.InfraConfigKeys, error) { + supportedConfigKeyMap := util.GetConfigKeysMapForPlatform(platformName) + cpuConfigKeys := impl.getCPUConfigFactory().getConfigKeys() + if err := impl.getCPUConfigFactory().validate(platformConfigurations, defaultConfigurations); err != nil { + for _, cpuConfigKey := range cpuConfigKeys { + supportedConfigKeyMap = supportedConfigKeyMap.MarkUnConfigured(cpuConfigKey) + } + if !skipError { + return supportedConfigKeyMap, err + } + } else { + for _, cpuConfigKey := range cpuConfigKeys { + supportedConfigKeyMap = supportedConfigKeyMap.MarkConfigured(cpuConfigKey) + } + } + + memConfigKeys := impl.getMemoryConfigFactory().getConfigKeys() + if err := impl.getMemoryConfigFactory().validate(platformConfigurations, defaultConfigurations); err != nil { + for _, memConfigKey := range memConfigKeys { + supportedConfigKeyMap = supportedConfigKeyMap.MarkUnConfigured(memConfigKey) + } + if !skipError { + return supportedConfigKeyMap, err + } + } else { + for _, memConfigKey := range memConfigKeys { + supportedConfigKeyMap = supportedConfigKeyMap.MarkConfigured(memConfigKey) + } + } + + timeoutConfigKeys := impl.getTimeoutConfigFactory().getConfigKeys() + if err := impl.getTimeoutConfigFactory().validate(platformConfigurations, defaultConfigurations); err != nil { + for _, timeoutConfigKey := range timeoutConfigKeys { + supportedConfigKeyMap = supportedConfigKeyMap.MarkUnConfigured(timeoutConfigKey) + } + if !skipError { + return supportedConfigKeyMap, err + } + } else { + for _, timeoutConfigKey := range timeoutConfigKeys { + supportedConfigKeyMap = supportedConfigKeyMap.MarkConfigured(timeoutConfigKey) + } + } + + supportedConfigKeyMap, err := impl.validateEntConfig(supportedConfigKeyMap, platformConfigurations, defaultConfigurations, skipError) + if !skipError && err != nil { + return supportedConfigKeyMap, err + } + return supportedConfigKeyMap, nil +} + +func (impl *InfraConfigClientImpl) getConfigurationBean(infraProfileConfiguration *repository.InfraProfileConfigurationEntity, profileName string) (*v1.ConfigurationBean, error) { + valueString := infraProfileConfiguration.ValueString + // handling for old values + if len(valueString) == 0 && infraProfileConfiguration.Unit > 0 { + valueString = strconv.FormatFloat(infraProfileConfiguration.Value, 'f', -1, 64) + } + valueInterface, _, err := impl.convertValueStringToInterface(util.GetConfigKeyStr(infraProfileConfiguration.Key), valueString) + if err != nil { + return &v1.ConfigurationBean{}, err + } + return &v1.ConfigurationBean{ + ConfigurationBeanAbstract: v1.ConfigurationBeanAbstract{ + Id: infraProfileConfiguration.Id, + Key: util.GetConfigKeyStr(infraProfileConfiguration.Key), + Unit: util.GetUnitSuffixStr(infraProfileConfiguration.Key, infraProfileConfiguration.Unit), + ProfileId: infraProfileConfiguration.ProfilePlatformMapping.ProfileId, + Active: infraProfileConfiguration.Active, + ProfileName: profileName, + }, + Value: valueInterface, + }, nil +} + +func (impl *InfraConfigClientImpl) formatTypedValueAsString(configKey v1.ConfigKeyStr, configValue any) (string, error) { + switch configKey { + case v1.CPU_LIMIT, v1.CPU_REQUEST: + return impl.getCPUConfigFactory().formatTypedValueAsString(configValue) + case v1.MEMORY_LIMIT, v1.MEMORY_REQUEST: + return impl.getMemoryConfigFactory().formatTypedValueAsString(configValue) + case v1.TIME_OUT: + return impl.getTimeoutConfigFactory().formatTypedValueAsString(configValue) + default: + return impl.formatTypedValueAsStringEnt(configKey, configValue) + } +} + +// convertValueStringToInterface converts valueString to interface{} based on key +func (impl *InfraConfigClientImpl) convertValueStringToInterface(configKey v1.ConfigKeyStr, valueString string) (any, int, error) { + switch configKey { + case v1.CPU_LIMIT, v1.CPU_REQUEST: + return impl.getCPUConfigFactory().getValueFromString(valueString) + case v1.MEMORY_LIMIT, v1.MEMORY_REQUEST: + return impl.getMemoryConfigFactory().getValueFromString(valueString) + case v1.TIME_OUT: + return impl.getTimeoutConfigFactory().getValueFromString(valueString) + // Add more cases as needed for different config keys + default: + return impl.convertValueStringToInterfaceEnt(configKey, valueString) + } +} + +func (impl *InfraConfigClientImpl) HandlePostUpdateOperations(tx *pg.Tx, updatedInfraConfigs []*repository.InfraProfileConfigurationEntity) error { + for _, updatedInfraConfig := range updatedInfraConfigs { + switch util.GetConfigKeyStr(updatedInfraConfig.Key) { + case v1.CPU_LIMIT, v1.CPU_REQUEST: + if err := impl.getCPUConfigFactory().handlePostUpdateOperations(tx, updatedInfraConfig); err != nil { + return err + } + case v1.MEMORY_LIMIT, v1.MEMORY_REQUEST: + if err := impl.getMemoryConfigFactory().handlePostUpdateOperations(tx, updatedInfraConfig); err != nil { + return err + } + case v1.TIME_OUT: + if err := impl.getTimeoutConfigFactory().handlePostUpdateOperations(tx, updatedInfraConfig); err != nil { + return err + } + default: + if err := impl.handlePostUpdateOperationEnt(tx, updatedInfraConfig); err != nil { + return err + } + } + } + return nil +} + +func (impl *InfraConfigClientImpl) HandlePostCreateOperations(tx *pg.Tx, createdInfraConfigs []*repository.InfraProfileConfigurationEntity) error { + for _, createdInfraConfig := range createdInfraConfigs { + switch util.GetConfigKeyStr(createdInfraConfig.Key) { + case v1.CPU_LIMIT, v1.CPU_REQUEST: + if err := impl.getCPUConfigFactory().handlePostCreateOperations(tx, createdInfraConfig); err != nil { + return err + } + case v1.MEMORY_LIMIT, v1.MEMORY_REQUEST: + if err := impl.getMemoryConfigFactory().handlePostCreateOperations(tx, createdInfraConfig); err != nil { + return err + } + case v1.TIME_OUT: + if err := impl.getTimeoutConfigFactory().handlePostCreateOperations(tx, createdInfraConfig); err != nil { + return err + } + default: + if err := impl.handlePostCreateOperationEnt(tx, createdInfraConfig); err != nil { + return err + } + } + } + return nil +} + +func (impl *InfraConfigClientImpl) OverrideInfraConfig(infraConfiguration *v1.InfraConfig, configurationBean *v1.ConfigurationBean) (*v1.InfraConfig, error) { + switch configurationBean.Key { + case v1.CPU_LIMIT, v1.CPU_REQUEST: + return impl.getCPUConfigFactory().overrideInfraConfig(infraConfiguration, configurationBean) + case v1.MEMORY_LIMIT, v1.MEMORY_REQUEST: + return impl.getMemoryConfigFactory().overrideInfraConfig(infraConfiguration, configurationBean) + case v1.TIME_OUT: + return impl.getTimeoutConfigFactory().overrideInfraConfig(infraConfiguration, configurationBean) + default: + return impl.overrideInfraConfigEnt(infraConfiguration, configurationBean) + } +} + +func (impl *InfraConfigClientImpl) MergeInfraConfigurations(supportedConfigKey v1.ConfigKeyStr, profileConfiguration *v1.ConfigurationBean, defaultConfigurations []*v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + switch supportedConfigKey { + case v1.CPU_LIMIT: + return impl.getCPUConfigFactory().getAppliedConfiguration(v1.CPU_LIMIT, profileConfiguration, defaultConfigurations) + case v1.CPU_REQUEST: + return impl.getCPUConfigFactory().getAppliedConfiguration(v1.CPU_REQUEST, profileConfiguration, defaultConfigurations) + case v1.MEMORY_LIMIT: + return impl.getMemoryConfigFactory().getAppliedConfiguration(v1.MEMORY_LIMIT, profileConfiguration, defaultConfigurations) + case v1.MEMORY_REQUEST: + return impl.getMemoryConfigFactory().getAppliedConfiguration(v1.MEMORY_REQUEST, profileConfiguration, defaultConfigurations) + case v1.TIME_OUT: + return impl.getTimeoutConfigFactory().getAppliedConfiguration(v1.TIME_OUT, profileConfiguration, defaultConfigurations) + default: + return impl.mergeInfraConfigurationsEnt(supportedConfigKey, profileConfiguration, defaultConfigurations) + } +} + +func (impl *InfraConfigClientImpl) handleInfraConfigTriggerAudit(supportedConfigKeys v1.InfraConfigKeys, workflowId int, triggeredBy int32, infraConfig *v1.InfraConfig) error { + if supportedConfigKeys.IsSupported(v1.CPU_LIMIT) && supportedConfigKeys.IsSupported(v1.CPU_REQUEST) { + err := impl.getCPUConfigFactory().handleInfraConfigTriggerAudit(workflowId, triggeredBy, infraConfig) + if err != nil { + return err + } + } + if supportedConfigKeys.IsSupported(v1.MEMORY_LIMIT) && supportedConfigKeys.IsSupported(v1.MEMORY_REQUEST) { + err := impl.getMemoryConfigFactory().handleInfraConfigTriggerAudit(workflowId, triggeredBy, infraConfig) + if err != nil { + return err + } + } + if supportedConfigKeys.IsSupported(v1.TIME_OUT) { + err := impl.getTimeoutConfigFactory().handleInfraConfigTriggerAudit(workflowId, triggeredBy, infraConfig) + if err != nil { + return err + } + } + return impl.handleInfraConfigTriggerAuditEnt(supportedConfigKeys, workflowId, triggeredBy, infraConfig) +} diff --git a/pkg/infraConfig/config/infraConfigClient_ent.go b/pkg/infraConfig/config/infraConfigClient_ent.go new file mode 100644 index 0000000000..f4a9e2547a --- /dev/null +++ b/pkg/infraConfig/config/infraConfigClient_ent.go @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "fmt" + v1 "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/go-pg/pg" +) + +type InfraConfigEntClient interface{} + +func (impl *InfraConfigClientImpl) getEntConfigurationUnits() (map[v1.ConfigKeyStr]map[string]v1.Unit, error) { + return make(map[v1.ConfigKeyStr]map[string]v1.Unit), nil +} + +func (impl *InfraConfigClientImpl) formatTypedValueAsStringEnt(configKey v1.ConfigKeyStr, configValue any) (string, error) { + // Default case, return error for an unsupported key + return "", fmt.Errorf("config key %q not supported", configKey) +} + +func (impl *InfraConfigClientImpl) validateEntConfig(supportedConfigKeyMap v1.InfraConfigKeys, platformConfigurations, defaultConfigurations []*v1.ConfigurationBean, skipError bool) (v1.InfraConfigKeys, error) { + return supportedConfigKeyMap, nil +} + +func (impl *InfraConfigClientImpl) convertValueStringToInterfaceEnt(configKey v1.ConfigKeyStr, valueString string) (any, int, error) { + // Default case, return error for an unsupported key + return nil, 0, fmt.Errorf("config key %q not supported", configKey) +} + +func (impl *InfraConfigClientImpl) handlePostUpdateOperationEnt(tx *pg.Tx, updatedInfraConfig *repository.InfraProfileConfigurationEntity) error { + // Default case, return error for an unsupported key + return fmt.Errorf("config key %q not supported", updatedInfraConfig.Key) +} + +func (impl *InfraConfigClientImpl) handlePostCreateOperationEnt(tx *pg.Tx, createdInfraConfig *repository.InfraProfileConfigurationEntity) error { + return fmt.Errorf("config key %q not supported", createdInfraConfig.Key) +} + +func (impl *InfraConfigClientImpl) getInfraConfigEntEntities(profileId int, infraConfig *v1.InfraConfig) ([]*repository.InfraProfileConfigurationEntity, error) { + return make([]*repository.InfraProfileConfigurationEntity, 0), nil +} + +func (impl *InfraConfigClientImpl) overrideInfraConfigEnt(infraConfiguration *v1.InfraConfig, configurationBean *v1.ConfigurationBean) (*v1.InfraConfig, error) { + return nil, fmt.Errorf("config key %q not supported", configurationBean.Key) +} + +func (impl *InfraConfigClientImpl) mergeInfraConfigurationsEnt(supportedConfigKey v1.ConfigKeyStr, profileConfiguration *v1.ConfigurationBean, defaultConfigurations []*v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + return nil, fmt.Errorf("config key %q not supported", supportedConfigKey) +} + +func (impl *InfraConfigClientImpl) handleInfraConfigTriggerAuditEnt(supportedConfigKeys v1.InfraConfigKeys, workflowId int, triggeredBy int32, infraConfig *v1.InfraConfig) error { + return nil +} diff --git a/pkg/infraConfig/config/infra_common_config.go b/pkg/infraConfig/config/infra_common_config.go new file mode 100644 index 0000000000..f22c27c802 --- /dev/null +++ b/pkg/infraConfig/config/infra_common_config.go @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + internalUtil "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/units" + "github.com/devtron-labs/devtron/pkg/infraConfig/util" + globalUtil "github.com/devtron-labs/devtron/util" + "github.com/devtron-labs/devtron/util/sliceUtil" + "k8s.io/apimachinery/pkg/api/resource" + "net/http" + "reflect" + "strconv" + "strings" +) + +type nativeValueKind interface { + float64 +} + +func validLimitRequestForCPUorMem(lim, limFactor, req, reqFactor float64) bool { + // this condition should be true for the valid case => (lim/req)*(lf/rf) >= 1 + limitToReqRatio := lim / req + convFactor := limFactor / reqFactor + return limitToReqRatio*convFactor >= 1 +} + +// parseCPUorMemoryValue parses the quantity that has number values string and returns the value and unitType +// returns error if parsing fails +func parseCPUorMemoryValue[T units.UnitStrService](quantity string) (float64, T, error) { + var unitType T + positive, _, num, denom, suffix, err := parseQuantityString(quantity) + if err != nil { + return 0, unitType, err + } + unitType = T(suffix) + if !positive { + errMsg := "negative value not allowed for cpu limits" + return 0, unitType, internalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + valStr := num + if denom != "" { + valStr = num + "." + denom + } + + val, err := strconv.ParseFloat(valStr, 64) + if err != nil { + return val, unitType, err + } + // currently we are not supporting exponential values upto 2 decimals + val = globalUtil.TruncateFloat(val, 2) + return val, unitType, nil +} + +// parseQuantityString is a fast scanner for quantity values. +// this parsing is only for cpu and mem resources +func parseQuantityString(str string) (positive bool, value, num, denom, suffix string, err error) { + positive = true + pos := 0 + end := len(str) + + // handle leading sign + if pos < end { + switch str[0] { + case '-': + positive = false + pos++ + case '+': + pos++ + } + } + + // strip leading zeros +Zeroes: + for i := pos; ; i++ { + if i >= end { + num = "0" + value = num + return + } + switch str[i] { + case '0': + pos++ + default: + break Zeroes + } + } + + // extract the numerator +Num: + for i := pos; ; i++ { + if i >= end { + num = str[pos:end] + value = str[0:end] + return + } + switch str[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + num = str[pos:i] + pos = i + break Num + } + } + + // if we stripped all numerator positions, always return 0 + if len(num) == 0 { + num = "0" + } + + // handle a denominator + if pos < end && str[pos] == '.' { + pos++ + Denom: + for i := pos; ; i++ { + if i >= end { + denom = str[pos:end] + value = str[0:end] + return + } + switch str[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + denom = str[pos:i] + pos = i + break Denom + } + } + // TODO: we currently allow 1.G, but we may not want to in the future. + // if len(denom) == 0 { + // err = ErrFormatWrong + // return + // } + } + value = str[0:pos] + + // grab the elements of the suffix + suffixStart := pos + for i := pos; ; i++ { + if i >= end { + suffix = str[suffixStart:end] + return + } + if !strings.ContainsAny(str[i:i+1], "eEinumkKMGTP") { + pos = i + break + } + } + if pos < end { + switch str[pos] { + case '-', '+': + pos++ + } + } +Suffix: + for i := pos; ; i++ { + if i >= end { + suffix = str[suffixStart:end] + return + } + switch str[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + default: + break Suffix + } + } + // we encountered a non decimal in the Suffix loop, but the last character + // was not a valid exponent + err = resource.ErrFormatWrong + return +} + +func filterSupportedConfigurations(platformName string, defaultConfigurations []*v1.ConfigurationBean) []*v1.ConfigurationBean { + // If not, fallback to the default platform configurations + filteredConfigurationBean := make([]*v1.ConfigurationBean, 0) + if len(defaultConfigurations) == 0 { + return filteredConfigurationBean + } + // Get the supported configuration keys for the platform + supportedConfigKeys := util.GetConfigKeysMapForPlatform(platformName) + for _, configuration := range defaultConfigurations { + if supportedConfigKeys.IsSupported(configuration.Key) { + filteredConfigurationBean = append(filteredConfigurationBean, configuration) + } + // Skip the not supported configurations for the platform + } + return filteredConfigurationBean +} + +func getInheritedConfigurations[T nativeValueKind](defaultConfigBeanAbstract v1.ConfigurationBeanAbstract, profileData, defaultData T, + profileConfigBean, defaultConfigBean *v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + if !reflect.ValueOf(profileData).IsZero() { + // CASE 1: If data is found in profileBean, but the globalProfile does not have any data, + // then the merged data configuration will be the profile configuration. + return getAppliedConfigurationBean(profileConfigBean, profileData, + v1.OVERRIDDEN, sliceUtil.GetSliceOf(profileConfigBean.Id)), nil + } else if !reflect.ValueOf(defaultData).IsZero() { + // CASE 2: If data is not found in profileBean, + // then the merged data configuration will be the global profile. + return getAppliedConfigurationBean(defaultConfigBean, defaultData, + v1.INHERITING_GLOBAL_PROFILE, sliceUtil.GetSliceOf(defaultConfigBean.Id)), nil + } else { + // CASE 3: If data is not found in profileBean as well as in global profile, + // then the merged data configuration will be the profile configuration. + if profileConfigBean != nil && profileConfigBean.Active { + // OVERRIDDEN is used, for a missing configuration case if the profile configuration is active. + // - the configuration is active in the profile. + // - whenever the default gets updated, it will have no impact on the profile. + // - only when the profile configuration is updated, it will change. + return getMissingConfigurationBean[T](defaultConfigBeanAbstract, profileConfigBean, + v1.OVERRIDDEN, sliceUtil.GetSliceOf(profileConfigBean.Id)), nil + } else { + // INHERITING_GLOBAL_PROFILE is used, for a missing configuration case if the profile configuration is not active. + // - the configuration is not active in the profile. + // - whenever the default gets updated, it will be inherited by the profile. + var appliedConfigIds []int + if defaultConfigBean != nil { + appliedConfigIds = sliceUtil.GetSliceOf(defaultConfigBean.Id) + } + return getMissingConfigurationBean[T](defaultConfigBeanAbstract, defaultConfigBean, + v1.INHERITING_GLOBAL_PROFILE, appliedConfigIds), nil + } + } +} + +func getAppliedConfigurationBean[T nativeValueKind](configBean *v1.ConfigurationBean, value T, + stateType v1.ConfigStateType, appliedConfigIds []int) *v1.ConfigurationBean { + // make a copy of the data and update the value + newConfigBean := configBean.DeepCopy() + newConfigBean.Value = value + if reflect.ValueOf(value).IsZero() { + newConfigBean.Count = 0 + } else { + newConfigBean.Count = 1 + } + newConfigBean.ConfigState = stateType + newConfigBean.AppliedConfigIds = sliceUtil.GetUniqueElements(appliedConfigIds) + return newConfigBean +} + +func getMissingConfigurationBean[T nativeValueKind](defaultConfigBeanAbstract v1.ConfigurationBeanAbstract, + defaultConfigBean *v1.ConfigurationBean, configState v1.ConfigStateType, appliedConfigIds []int) *v1.ConfigurationBean { + if defaultConfigBean == nil { + defaultConfigBean = &v1.ConfigurationBean{} + defaultConfigBean.ConfigurationBeanAbstract = defaultConfigBeanAbstract + } + var emptyValue T + newConfigBean := defaultConfigBean.DeepCopy() + newConfigBean.Value = emptyValue + newConfigBean.Count = 0 + newConfigBean.ConfigState = configState + newConfigBean.AppliedConfigIds = sliceUtil.GetUniqueElements(appliedConfigIds) + return newConfigBean +} diff --git a/pkg/infraConfig/units/units_test.go b/pkg/infraConfig/config/infra_common_config_test.go similarity index 91% rename from pkg/infraConfig/units/units_test.go rename to pkg/infraConfig/config/infra_common_config_test.go index f4c8c9269e..23f073b631 100644 --- a/pkg/infraConfig/units/units_test.go +++ b/pkg/infraConfig/config/infra_common_config_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package units +package config import ( "fmt" @@ -24,12 +24,11 @@ import ( // todo: add more test cases func TestParseQuantityString(t *testing.T) { memLimit := "01.400Gi" - pos, val, num, denom, suf, err := ParseQuantityString(memLimit) + pos, val, num, denom, suf, err := parseQuantityString(memLimit) fmt.Println("pos: ", pos) fmt.Println("val: ", val) fmt.Println("num: ", num) fmt.Println("denom: ", denom) fmt.Println("suf: ", suf) fmt.Println("err: ", err) - } diff --git a/pkg/infraConfig/config/infra_config_factory.go b/pkg/infraConfig/config/infra_config_factory.go new file mode 100644 index 0000000000..e194ba8dfb --- /dev/null +++ b/pkg/infraConfig/config/infra_config_factory.go @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "github.com/devtron-labs/devtron/pkg/config/read" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/devtron-labs/devtron/pkg/infraConfig/units" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" + "github.com/devtron-labs/devtron/pkg/variables" + "github.com/go-pg/pg" + "go.uber.org/zap" +) + +type configFactory[T any] interface { + validate(platformConfigurations, defaultConfigurations []*v1.ConfigurationBean) error + getConfigKeys() []v1.ConfigKeyStr + getSupportedUnits() map[v1.ConfigKeyStr]map[string]v1.Unit + + getInfraConfigEntities(infraConfig *v1.InfraConfig, profileId int, platformName string) ([]*repository.InfraProfileConfigurationEntity, error) + getValueFromString(valueString string) (T, int, error) + getValueFromBean(configurationBean *v1.ConfigurationBean) (T, error) + formatTypedValueAsString(configValue any) (string, error) + overrideInfraConfig(infraConfiguration *v1.InfraConfig, configurationBean *v1.ConfigurationBean) (*v1.InfraConfig, error) + getAppliedConfiguration(key v1.ConfigKeyStr, infraConfiguration *v1.ConfigurationBean, defaultConfigurations []*v1.ConfigurationBean) (*v1.ConfigurationBean, error) + handlePostCreateOperations(tx *pg.Tx, createdInfraConfig *repository.InfraProfileConfigurationEntity) error + handlePostUpdateOperations(tx *pg.Tx, updatedInfraConfig *repository.InfraProfileConfigurationEntity) error + handlePostDeleteOperations(tx *pg.Tx, deletedInfraConfig *repository.InfraProfileConfigurationEntity) error + handleInfraConfigTriggerAudit(workflowId int, triggeredBy int32, infraConfig *v1.InfraConfig) error + resolveScopeVariablesForAppliedConfiguration(scope resourceQualifiers.Scope, configuration *v1.ConfigurationBean) (*v1.ConfigurationBean, map[string]string, error) +} + +type configFactories struct { + cpuConfigFactory configFactory[float64] + memConfigFactory configFactory[float64] + timeoutConfigFactory configFactory[float64] + configEntFactories +} + +type unitFactories struct { + cpuUnitFactory units.UnitService[float64] + memUnitFactory units.UnitService[float64] + timeUnitFactory units.UnitService[float64] + unitEntFactories +} + +func getConfigFactory(logger *zap.SugaredLogger, + scopedVariableManager variables.ScopedVariableManager, + configReadService read.ConfigReadService) *configFactories { + return &configFactories{ + cpuConfigFactory: newCPUClientImpl(logger), + memConfigFactory: newMemClientImpl(logger), + timeoutConfigFactory: newTimeoutClientImpl(logger), + configEntFactories: newConfigEntFactories(logger, scopedVariableManager, configReadService), + } +} + +func getUnitFactoryMap(logger *zap.SugaredLogger) *unitFactories { + cpuUnitFactory := units.NewCPUUnitFactory(logger) + memUnitFactory := units.NewMemoryUnitFactory(logger) + timeUnitFactory := units.NewTimeUnitFactory(logger) + unitFactoryMap := &unitFactories{ + cpuUnitFactory: cpuUnitFactory, + memUnitFactory: memUnitFactory, + timeUnitFactory: timeUnitFactory, + unitEntFactories: newUnitEntFactories(logger), + } + return unitFactoryMap +} diff --git a/pkg/infraConfig/config/infra_config_factory_ent.go b/pkg/infraConfig/config/infra_config_factory_ent.go new file mode 100644 index 0000000000..18a0fe191a --- /dev/null +++ b/pkg/infraConfig/config/infra_config_factory_ent.go @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "github.com/devtron-labs/devtron/pkg/config/read" + "github.com/devtron-labs/devtron/pkg/variables" + "go.uber.org/zap" +) + +type configEntFactories struct { +} + +type unitEntFactories struct { +} + +func newConfigEntFactories(logger *zap.SugaredLogger, + scopedVariableManager variables.ScopedVariableManager, + configReadService read.ConfigReadService) configEntFactories { + return configEntFactories{} +} + +func newUnitEntFactories(logger *zap.SugaredLogger) unitEntFactories { + return unitEntFactories{} +} diff --git a/pkg/infraConfig/config/infra_cpu_config.go b/pkg/infraConfig/config/infra_cpu_config.go new file mode 100644 index 0000000000..6e0a2a66dc --- /dev/null +++ b/pkg/infraConfig/config/infra_cpu_config.go @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "fmt" + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/adapter" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/errors" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/devtron-labs/devtron/pkg/infraConfig/units" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" + globalUtil "github.com/devtron-labs/devtron/util" + "github.com/go-pg/pg" + "go.uber.org/zap" + "net/http" + "reflect" + "strconv" +) + +type cpuClientImpl struct { + logger *zap.SugaredLogger + cpuUnitFactory units.UnitService[float64] +} + +func newCPUClientImpl(logger *zap.SugaredLogger) *cpuClientImpl { + return &cpuClientImpl{ + logger: logger, + cpuUnitFactory: units.NewCPUUnitFactory(logger), + } +} + +func (impl *cpuClientImpl) getCPUClient() units.UnitService[float64] { + return impl.cpuUnitFactory +} + +// mergedConfiguration: +// - If configurations are not found in profileBean, +// then the merged cpu configuration will be the global profile platform +// (either the same platform or default platform of globalProfile). +// - If configurations are found in profileBean, +// then the merged cpu configuration will be the profile configuration. +// +// Inputs: +// - cpuLimit/ cpuReq: *bean.ConfigurationBean +// - defaultConfigurations: []*bean.ConfigurationBean +// +// Outputs: +// - *bean.ConfigurationBean (merged cpuLimit/ cpuReq configuration) +// - error +func (impl *cpuClientImpl) getAppliedConfiguration(key v1.ConfigKeyStr, profileConfigBean *v1.ConfigurationBean, defaultConfigurations []*v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + profileData, err := impl.getValueFromBean(profileConfigBean) + if err != nil { + impl.logger.Errorw("error in getting cpu config data", "error", err, "cpuConfig", profileConfigBean) + return profileConfigBean, err + } + defaultConfigBean, defaultData, err := impl.getConfigBeanAndDataForKey(key, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in getting cpu default config data", "error", err, "cpuConfig", defaultConfigBean) + return profileConfigBean, err + } + return impl.getInheritedConfigurations(key, profileData, defaultData, profileConfigBean, defaultConfigBean) +} + +func (impl *cpuClientImpl) getConfigBeanAndDataForKey(key v1.ConfigKeyStr, configurations []*v1.ConfigurationBean) (configBean *v1.ConfigurationBean, configData float64, err error) { + for _, configuration := range configurations { + if configuration.Key == key { + configBean = configuration + configData, err = impl.getValueFromBean(configBean) + if err != nil { + impl.logger.Errorw("error in getting cpu config data", "error", err, "cpuConfig", configBean) + return configBean, configData, err + } + return configBean, configData, nil + } + } + return configBean, configData, nil +} + +func (impl *cpuClientImpl) getInheritedConfigurations(key v1.ConfigKeyStr, profileData, defaultData float64, + profileConfigBean, defaultConfigBean *v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + defaultConfigBeanAbstract := v1.ConfigurationBeanAbstract{ + Key: key, + Unit: impl.cpuUnitFactory.GetDefaultUnitSuffix(), + } + return getInheritedConfigurations(defaultConfigBeanAbstract, profileData, defaultData, profileConfigBean, defaultConfigBean) +} + +func (impl *cpuClientImpl) validate(platformConfigurations, defaultConfigurations []*v1.ConfigurationBean) (err error) { + var cpuLimit, cpuReq *v1.ConfigurationBean + for _, configuration := range platformConfigurations { + // get cpu limit and req + switch configuration.Key { + case v1.CPU_LIMIT: + cpuLimit = configuration + case v1.CPU_REQUEST: + cpuReq = configuration + } + } + cpuLimit, err = impl.getAppliedConfiguration(v1.CPU_LIMIT, cpuLimit, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in merging cpu limit configurations", "error", err, "cpuLimit", cpuLimit) + return err + } + cpuReq, err = impl.getAppliedConfiguration(v1.CPU_REQUEST, cpuReq, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in merging cpu request configurations", "error", err, "cpuReq", cpuReq) + return err + } + if !cpuLimit.IsEmpty() && !cpuReq.IsEmpty() { + err = impl.validCPUConfig(cpuLimit, cpuReq) + if err != nil { + return err + } + } + return nil +} + +func (impl *cpuClientImpl) validCPUConfig(cpuLimit, cpuReq *v1.ConfigurationBean) error { + cpuLimitValue, err := impl.getValueFromBean(cpuLimit) + if err != nil { + impl.logger.Errorw("error in getting cpu limit value", "error", err, "cpuLimit", cpuLimit) + return err + } + cpuLimitConfiguration := adapter.GetGenericConfigurationBean(cpuLimit, cpuLimitValue) + cpuLimitConfig, err := impl.getCPUClient().Validate(cpuLimitConfiguration) + if err != nil { + impl.logger.Errorw("error in validating cpu limit", "error", err, "cpuLimit", cpuLimit) + return err + } + cpuReqValue, err := impl.getValueFromBean(cpuReq) + if err != nil { + impl.logger.Errorw("error in getting cpu request value", "error", err, "cpuReq", cpuReq) + return err + } + cpuReqConfiguration := adapter.GetGenericConfigurationBean(cpuReq, cpuReqValue) + cpuReqConfig, err := impl.getCPUClient().Validate(cpuReqConfiguration) + if err != nil { + impl.logger.Errorw("error in validating cpu request", "error", err, "cpuReq", cpuReq) + return err + } + if !cpuLimitConfig.IsEmpty() && !cpuReqConfig.IsEmpty() { + if !impl.validCPULimitRequest(cpuLimitConfig.Value, cpuLimitConfig.Unit.ConversionFactor, cpuReqConfig.Value, cpuReqConfig.Unit.ConversionFactor) { + impl.logger.Errorw("error in comparing cpu limit and request", "cpuLimit", cpuLimitConfig, "cpuReq", cpuReqConfig) + return util.NewApiError(http.StatusBadRequest, errors.CPULimReqErrorCompErr, errors.CPULimReqErrorCompErr) + } + } + return nil +} + +func (impl *cpuClientImpl) validCPULimitRequest(lim, limFactor, req, reqFactor float64) bool { + return validLimitRequestForCPUorMem(lim, limFactor, req, reqFactor) +} + +func (impl *cpuClientImpl) getConfigKeys() []v1.ConfigKeyStr { + return []v1.ConfigKeyStr{v1.CPU_LIMIT, v1.CPU_REQUEST} +} + +func (impl *cpuClientImpl) getSupportedUnits() map[v1.ConfigKeyStr]map[string]v1.Unit { + supportedUnitsMap := make(map[v1.ConfigKeyStr]map[string]v1.Unit) + supportedUnits := impl.getCPUClient().GetAllUnits() + for _, configKey := range impl.getConfigKeys() { + supportedUnitsMap[configKey] = supportedUnits + } + return supportedUnitsMap +} + +func (impl *cpuClientImpl) getInfraConfigEntities(infraConfig *v1.InfraConfig, profileId int, platformName string) ([]*repository.InfraProfileConfigurationEntity, error) { + defaultConfigurations := make([]*repository.InfraProfileConfigurationEntity, 0) + cpuLimitValue, unitType, err := parseCPUorMemoryValue[unitsBean.CPUUnitStr](infraConfig.CiLimitCpu) + if err != nil { + return defaultConfigurations, err + } + cpuLimitParsedValue, err := impl.getCPUClient().ParseValAndUnit(cpuLimitValue, unitType.GetUnitSuffix()) + if err != nil { + return defaultConfigurations, err + } + cpuLimit := adapter.NewInfraProfileConfigEntity(v1.CPU_LIMIT, profileId, platformName, cpuLimitParsedValue) + defaultConfigurations = append(defaultConfigurations, cpuLimit) + + cpuReqValue, unitType, err := parseCPUorMemoryValue[unitsBean.CPUUnitStr](infraConfig.CiReqCpu) + if err != nil { + return defaultConfigurations, err + } + cpuReqParsedValue, err := impl.getCPUClient().ParseValAndUnit(cpuReqValue, unitType.GetUnitSuffix()) + if err != nil { + return defaultConfigurations, err + } + cpuReq := adapter.NewInfraProfileConfigEntity(v1.CPU_REQUEST, profileId, platformName, cpuReqParsedValue) + defaultConfigurations = append(defaultConfigurations, cpuReq) + return defaultConfigurations, nil +} + +func (impl *cpuClientImpl) getValueFromString(valueString string) (float64, int, error) { + // Convert string to float64 and truncate to 2 decimal places + valueFloat, err := strconv.ParseFloat(valueString, 64) + if err != nil { + return 0, 0, err + } + truncateValue := globalUtil.TruncateFloat(valueFloat, 2) + return truncateValue, impl.getValueCount(truncateValue), nil // Returning float64 for resource values +} + +func (impl *cpuClientImpl) overrideInfraConfig(infraConfiguration *v1.InfraConfig, configurationBean *v1.ConfigurationBean) (*v1.InfraConfig, error) { + cpuConfigData, err := impl.getValueFromBean(configurationBean) + if err != nil { + return infraConfiguration, err + } + var cpuInfraConfigData string + if configurationBean.Unit == unitsBean.CORE.String() { + cpuInfraConfigData = fmt.Sprintf("%v", cpuConfigData) + } else { + cpuInfraConfigData = fmt.Sprintf("%v%v", cpuConfigData, configurationBean.Unit) + } + if configurationBean.Key == v1.CPU_REQUEST { + infraConfiguration = infraConfiguration.SetCiReqCpu(cpuInfraConfigData) + } else if configurationBean.Key == v1.CPU_LIMIT { + infraConfiguration = infraConfiguration.SetCiLimitCpu(cpuInfraConfigData) + } else { + errMsg := fmt.Sprintf("invalid key %q for cpu configuration", configurationBean.Key) + return infraConfiguration, util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + return infraConfiguration, nil +} + +func (impl *cpuClientImpl) getValueFromBean(configurationBean *v1.ConfigurationBean) (float64, error) { + if configurationBean == nil { + return 0, nil + } + valueString, err := impl.formatTypedValueAsString(configurationBean.Value) + if err != nil { + return 0, err + } + cpuConfigData, _, err := impl.getValueFromString(valueString) + if err != nil { + impl.logger.Errorw("error in getting config data", "error", err, "config", configurationBean) + return 0, err + } + return cpuConfigData, nil +} + +func (impl *cpuClientImpl) formatTypedValueAsString(configValue any) (string, error) { + var valueFloat float64 + // Handle string input or directly as float64 + switch v := configValue.(type) { + case float64: + valueFloat = v + default: + errMsg := fmt.Sprintf("invalid value for cpu configuration: %v", configValue) + return "", util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + // Truncate and format the float value + truncateValue := globalUtil.TruncateFloat(valueFloat, 2) + return strconv.FormatFloat(truncateValue, 'f', -1, 64), nil +} + +func (impl *cpuClientImpl) getValueCount(value float64) int { + if reflect.ValueOf(value).IsZero() { + return 0 + } + return 1 +} + +func (impl *cpuClientImpl) handlePostCreateOperations(tx *pg.Tx, createdInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *cpuClientImpl) handlePostUpdateOperations(tx *pg.Tx, updatedInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *cpuClientImpl) handlePostDeleteOperations(tx *pg.Tx, deletedInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *cpuClientImpl) handleInfraConfigTriggerAudit(workflowId int, triggeredBy int32, infraConfig *v1.InfraConfig) error { + return nil +} + +func (impl *cpuClientImpl) resolveScopeVariablesForAppliedConfiguration(scope resourceQualifiers.Scope, configuration *v1.ConfigurationBean) (*v1.ConfigurationBean, map[string]string, error) { + return configuration, nil, nil +} diff --git a/pkg/infraConfig/config/infra_mem_config.go b/pkg/infraConfig/config/infra_mem_config.go new file mode 100644 index 0000000000..ad0d31160b --- /dev/null +++ b/pkg/infraConfig/config/infra_mem_config.go @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "fmt" + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/adapter" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/errors" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/devtron-labs/devtron/pkg/infraConfig/units" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" + globalUtil "github.com/devtron-labs/devtron/util" + "github.com/go-pg/pg" + "go.uber.org/zap" + "net/http" + "reflect" + "strconv" +) + +type memClientImpl struct { + logger *zap.SugaredLogger + memUnitFactory units.UnitService[float64] +} + +func newMemClientImpl(logger *zap.SugaredLogger) *memClientImpl { + return &memClientImpl{ + logger: logger, + memUnitFactory: units.NewMemoryUnitFactory(logger), + } +} + +func (impl *memClientImpl) getMemoryClient() units.UnitService[float64] { + return impl.memUnitFactory +} + +// mergedConfiguration: +// - If configurations are not found in profileBean, +// then the merged memory configuration will be the global profile platform +// (either the same platform or default platform of globalProfile). +// - If configurations are found in profileBean, +// then the merged memory configuration will be the profile configuration. +// +// Inputs: +// - memLimit: *bean.ConfigurationBean +// - memReq: *bean.ConfigurationBean +// - defaultConfigurations: []*bean.ConfigurationBean +// +// Outputs: +// - *bean.ConfigurationBean (merged memLimit configuration) +// - *bean.ConfigurationBean (merged memReq configuration) +// - error +func (impl *memClientImpl) getAppliedConfiguration(key v1.ConfigKeyStr, profileConfigBean *v1.ConfigurationBean, defaultConfigurations []*v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + profileData, err := impl.getValueFromBean(profileConfigBean) + if err != nil { + impl.logger.Errorw("error in getting memory config data", "error", err, "memoryConfig", profileConfigBean) + return profileConfigBean, err + } + defaultConfigBean, defaultData, err := impl.getConfigBeanAndDataForKey(key, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in getting memory config data", "error", err, "memoryConfig", defaultConfigurations) + return profileConfigBean, err + } + return impl.getInheritedConfigurations(key, profileData, defaultData, profileConfigBean, defaultConfigBean) +} + +func (impl *memClientImpl) getConfigBeanAndDataForKey(key v1.ConfigKeyStr, configurations []*v1.ConfigurationBean) (configBean *v1.ConfigurationBean, configData float64, err error) { + for _, configuration := range configurations { + if configuration.Key == key { + configBean = configuration + configData, err = impl.getValueFromBean(configBean) + if err != nil { + impl.logger.Errorw("error in getting memory config data", "error", err, "memoryConfig", configBean) + return configBean, configData, err + } + return configBean, configData, nil + } + } + return configBean, configData, nil +} + +func (impl *memClientImpl) getInheritedConfigurations(key v1.ConfigKeyStr, profileData, defaultData float64, + profileConfigBean, defaultConfigBean *v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + defaultConfigBeanAbstract := v1.ConfigurationBeanAbstract{ + Key: key, + Unit: impl.memUnitFactory.GetDefaultUnitSuffix(), + } + return getInheritedConfigurations(defaultConfigBeanAbstract, profileData, defaultData, profileConfigBean, defaultConfigBean) +} + +func (impl *memClientImpl) validate(platformConfigurations, defaultConfigurations []*v1.ConfigurationBean) (err error) { + var memLimit, memReq *v1.ConfigurationBean + for _, configuration := range platformConfigurations { + // get memory limit and req + switch configuration.Key { + case v1.MEMORY_LIMIT: + memLimit = configuration + case v1.MEMORY_REQUEST: + memReq = configuration + } + } + memLimit, err = impl.getAppliedConfiguration(v1.MEMORY_LIMIT, memLimit, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in merging memory limit configurations", "error", err, "memLimit", memLimit) + return err + } + memReq, err = impl.getAppliedConfiguration(v1.MEMORY_REQUEST, memReq, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in merging memory request configurations", "error", err, "memReq", memReq) + return err + } + if !memLimit.IsEmpty() && !memReq.IsEmpty() { + err = impl.validMemoryBean(memLimit, memReq) + if err != nil { + impl.logger.Errorw("error in validating memory", "error", err, "memLimit", memLimit, "memReq", memReq) + return err + } + } + return nil +} + +func (impl *memClientImpl) validMemoryBean(memLimit, memReq *v1.ConfigurationBean) error { + memLimitValue, err := impl.getValueFromBean(memLimit) + if err != nil { + impl.logger.Errorw("error in getting memory limit value", "error", err, "memLimit", memLimit) + return err + } + memLimitConfiguration := adapter.GetGenericConfigurationBean(memLimit, memLimitValue) + memLimitConfig, err := impl.getMemoryClient().Validate(memLimitConfiguration) + if err != nil { + impl.logger.Errorw("error in validating memory limit", "error", err, "memLimit", memLimit) + return err + } + memReqValue, err := impl.getValueFromBean(memReq) + if err != nil { + impl.logger.Errorw("error in getting memory request value", "error", err, "memReq", memReq) + return err + } + memReqConfiguration := adapter.GetGenericConfigurationBean(memReq, memReqValue) + memReqConfig, err := impl.getMemoryClient().Validate(memReqConfiguration) + if err != nil { + impl.logger.Errorw("error in validating memory request", "error", err, "memReq", memReq) + return err + } + if !memLimitConfig.IsEmpty() && !memReqConfig.IsEmpty() { + if !impl.validMemoryLimitRequest(memLimitConfig.Value, memLimitConfig.Unit.ConversionFactor, memReqConfig.Value, memReqConfig.Unit.ConversionFactor) { + impl.logger.Errorw("error in comparing memory limit and request", "memLimit", memLimitConfig, "memReq", memReqConfig) + return util.NewApiError(http.StatusBadRequest, errors.MEMLimReqErrorCompErr, errors.MEMLimReqErrorCompErr) + } + } + return nil +} + +func (impl *memClientImpl) validMemoryLimitRequest(lim, limFactor, req, reqFactor float64) bool { + return validLimitRequestForCPUorMem(lim, limFactor, req, reqFactor) +} + +func (impl *memClientImpl) getConfigKeys() []v1.ConfigKeyStr { + return []v1.ConfigKeyStr{v1.MEMORY_LIMIT, v1.MEMORY_REQUEST} +} + +func (impl *memClientImpl) getSupportedUnits() map[v1.ConfigKeyStr]map[string]v1.Unit { + supportedUnitsMap := make(map[v1.ConfigKeyStr]map[string]v1.Unit) + supportedUnits := impl.getMemoryClient().GetAllUnits() + for _, configKey := range impl.getConfigKeys() { + supportedUnitsMap[configKey] = supportedUnits + } + return supportedUnitsMap +} + +func (impl *memClientImpl) getInfraConfigEntities(infraConfig *v1.InfraConfig, profileId int, platformName string) ([]*repository.InfraProfileConfigurationEntity, error) { + defaultConfigurations := make([]*repository.InfraProfileConfigurationEntity, 0) + memLimitValue, unitType, err := parseCPUorMemoryValue[unitsBean.MemoryUnitStr](infraConfig.CiLimitMem) + if err != nil { + return defaultConfigurations, err + } + memLimitParsedValue, err := impl.getMemoryClient().ParseValAndUnit(memLimitValue, unitType.GetUnitSuffix()) + if err != nil { + return defaultConfigurations, err + } + memLimit := adapter.NewInfraProfileConfigEntity(v1.MEMORY_LIMIT, profileId, platformName, memLimitParsedValue) + defaultConfigurations = append(defaultConfigurations, memLimit) + memReqValue, unitType, err := parseCPUorMemoryValue[unitsBean.MemoryUnitStr](infraConfig.CiReqMem) + if err != nil { + return defaultConfigurations, err + } + memReqParsedValue, err := impl.getMemoryClient().ParseValAndUnit(memReqValue, unitType.GetUnitSuffix()) + if err != nil { + return defaultConfigurations, err + } + memReq := adapter.NewInfraProfileConfigEntity(v1.MEMORY_REQUEST, profileId, platformName, memReqParsedValue) + defaultConfigurations = append(defaultConfigurations, memReq) + return defaultConfigurations, nil +} + +func (impl *memClientImpl) getValueFromString(valueString string) (float64, int, error) { + // Convert string to float64 and truncate to 2 decimal places + valueFloat, err := strconv.ParseFloat(valueString, 64) + if err != nil { + return 0, 0, err + } + truncateValue := globalUtil.TruncateFloat(valueFloat, 2) + return truncateValue, impl.getValueCount(truncateValue), nil // Returning float64 for resource values + +} + +func (impl *memClientImpl) overrideInfraConfig(infraConfiguration *v1.InfraConfig, configurationBean *v1.ConfigurationBean) (*v1.InfraConfig, error) { + memConfigData, err := impl.getValueFromBean(configurationBean) + if err != nil { + return infraConfiguration, err + } + var memInfraConfigData string + if configurationBean.Unit == unitsBean.BYTE.String() { + memInfraConfigData = fmt.Sprintf("%v", memConfigData) + } else { + memInfraConfigData = fmt.Sprintf("%v%v", memConfigData, configurationBean.Unit) + } + if configurationBean.Key == v1.MEMORY_REQUEST { + infraConfiguration = infraConfiguration.SetCiReqMem(memInfraConfigData) + } else if configurationBean.Key == v1.MEMORY_LIMIT { + infraConfiguration = infraConfiguration.SetCiLimitMem(memInfraConfigData) + } else { + errMsg := fmt.Sprintf("invalid key %q for memory configuration", configurationBean.Key) + return infraConfiguration, util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + return infraConfiguration, nil +} + +func (impl *memClientImpl) getValueFromBean(configurationBean *v1.ConfigurationBean) (float64, error) { + if configurationBean == nil { + return 0, nil + } + valueString, err := impl.formatTypedValueAsString(configurationBean.Value) + if err != nil { + return 0, err + } + memConfigData, _, err := impl.getValueFromString(valueString) + if err != nil { + impl.logger.Errorw("error in getting configMap data", "error", err, "configMap", configurationBean) + return 0, err + } + return memConfigData, nil +} + +func (impl *memClientImpl) formatTypedValueAsString(configValue any) (string, error) { + var valueFloat float64 + // Handle string input or directly as float64 + switch v := configValue.(type) { + case float64: + valueFloat = v + default: + errMsg := fmt.Sprintf("invalid value for memory configuration: %v", configValue) + return "", util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + // Truncate and format the float value + truncateValue := globalUtil.TruncateFloat(valueFloat, 2) + return strconv.FormatFloat(truncateValue, 'f', -1, 64), nil +} + +func (impl *memClientImpl) getValueCount(value float64) int { + if reflect.ValueOf(value).IsZero() { + return 0 + } + return 1 +} + +func (impl *memClientImpl) handlePostCreateOperations(tx *pg.Tx, createdInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *memClientImpl) handlePostUpdateOperations(tx *pg.Tx, updatedInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *memClientImpl) handlePostDeleteOperations(tx *pg.Tx, deletedInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *memClientImpl) handleInfraConfigTriggerAudit(workflowId int, triggeredBy int32, infraConfig *v1.InfraConfig) error { + return nil +} + +func (impl *memClientImpl) resolveScopeVariablesForAppliedConfiguration(scope resourceQualifiers.Scope, configuration *v1.ConfigurationBean) (*v1.ConfigurationBean, map[string]string, error) { + return configuration, nil, nil +} diff --git a/pkg/infraConfig/config/infra_timeout_config.go b/pkg/infraConfig/config/infra_timeout_config.go new file mode 100644 index 0000000000..d2e11cf564 --- /dev/null +++ b/pkg/infraConfig/config/infra_timeout_config.go @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +import ( + "fmt" + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/adapter" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/errors" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/devtron-labs/devtron/pkg/infraConfig/units" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" + "github.com/go-pg/pg" + "go.uber.org/zap" + "math" + "net/http" + "reflect" + "strconv" +) + +type timeoutClientImpl struct { + logger *zap.SugaredLogger + timeUnitFactory units.UnitService[float64] +} + +func newTimeoutClientImpl(logger *zap.SugaredLogger) *timeoutClientImpl { + return &timeoutClientImpl{ + logger: logger, + timeUnitFactory: units.NewTimeUnitFactory(logger), + } +} + +func (impl *timeoutClientImpl) getTimeClient() units.UnitService[float64] { + return impl.timeUnitFactory +} + +// mergedConfiguration: +// - If configurations are not found in profileBean, +// then the merged timeout configuration will be the global profile platform +// (either the same platform or default platform of globalProfile). +// - If configurations are found in profileBean, +// then the merged timeout configuration will be the profile configuration. +// +// Inputs: +// - timeOut: *bean.ConfigurationBean +// - defaultConfigurations: []*bean.ConfigurationBean +// +// Outputs: +// - *bean.ConfigurationBean (merged timeout configuration) +// - error +func (impl *timeoutClientImpl) getAppliedConfiguration(key v1.ConfigKeyStr, profileConfigBean *v1.ConfigurationBean, defaultConfigurations []*v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + profileData, err := impl.getValueFromBean(profileConfigBean) + if err != nil { + impl.logger.Errorw("error in getting timeout config data", "error", err, "timeoutConfig", profileConfigBean) + return profileConfigBean, err + } + defaultConfigBean, defaultData, err := impl.getConfigBeanAndDataForKey(key, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in getting timeout config data", "error", err, "timeoutConfig", defaultConfigurations) + return profileConfigBean, err + } + return impl.getInheritedConfigurations(key, profileData, defaultData, profileConfigBean, defaultConfigBean) +} + +func (impl *timeoutClientImpl) getConfigBeanAndDataForKey(key v1.ConfigKeyStr, configurations []*v1.ConfigurationBean) (configBean *v1.ConfigurationBean, configData float64, err error) { + for _, configuration := range configurations { + if configuration.Key == key { + configBean = configuration + configData, err = impl.getValueFromBean(configBean) + if err != nil { + impl.logger.Errorw("error in getting timeout config data", "error", err, "timeoutConfig", configBean) + return configBean, configData, err + } + return configBean, configData, nil + } + } + return configBean, configData, nil +} + +func (impl *timeoutClientImpl) getInheritedConfigurations(key v1.ConfigKeyStr, profileData, defaultData float64, + profileConfigBean, defaultConfigBean *v1.ConfigurationBean) (*v1.ConfigurationBean, error) { + defaultConfigBeanAbstract := v1.ConfigurationBeanAbstract{ + Key: key, + Unit: impl.timeUnitFactory.GetDefaultUnitSuffix(), + } + return getInheritedConfigurations(defaultConfigBeanAbstract, profileData, defaultData, profileConfigBean, defaultConfigBean) +} + +func (impl *timeoutClientImpl) validate(platformConfigurations, defaultConfigurations []*v1.ConfigurationBean) (err error) { + var timeOut *v1.ConfigurationBean + for _, configuration := range platformConfigurations { + switch configuration.Key { + case v1.TIME_OUT: + timeOut = configuration + } + } + timeOut, err = impl.getAppliedConfiguration(v1.TIME_OUT, timeOut, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in merging time out configuration", "error", err, "timeOut", timeOut) + return err + } + if !timeOut.IsEmpty() { + err = impl.validateTimeOut(timeOut) + if err != nil { + impl.logger.Errorw("error in validating time out", "error", err, "timeOut", timeOut) + return err + } + } + return nil +} + +func (impl *timeoutClientImpl) validateTimeOut(timeOut *v1.ConfigurationBean) error { + timeOutValue, err := impl.getValueFromBean(timeOut) + if err != nil { + impl.logger.Errorw("error in getting time out data", "error", err, "timeOut", timeOut) + return err + } + timeOutConfiguration := adapter.GetGenericConfigurationBean(timeOut, timeOutValue) + _, err = impl.getTimeClient().Validate(timeOutConfiguration) + if err != nil { + impl.logger.Errorw("error in validating time out unit", "error", err, "timeOut", timeOut) + return err + } + return nil +} + +func (impl *timeoutClientImpl) getConfigKeys() []v1.ConfigKeyStr { + return []v1.ConfigKeyStr{v1.TIME_OUT} +} + +func (impl *timeoutClientImpl) getSupportedUnits() map[v1.ConfigKeyStr]map[string]v1.Unit { + supportedUnitsMap := make(map[v1.ConfigKeyStr]map[string]v1.Unit) + supportedUnits := impl.getTimeClient().GetAllUnits() + for _, configKey := range impl.getConfigKeys() { + supportedUnitsMap[configKey] = supportedUnits + } + return supportedUnitsMap +} + +func (impl *timeoutClientImpl) getInfraConfigEntities(infraConfig *v1.InfraConfig, profileId int, platformName string) ([]*repository.InfraProfileConfigurationEntity, error) { + defaultConfigurations := make([]*repository.InfraProfileConfigurationEntity, 0) + timeoutParsedValue, err := impl.getTimeClient().ParseValAndUnit(infraConfig.CiDefaultTimeout, unitsBean.SecondStr.GetUnitSuffix()) + if err != nil { + return defaultConfigurations, err + } + timeoutConfig := adapter.NewInfraProfileConfigEntity(v1.TIME_OUT, profileId, platformName, timeoutParsedValue) + defaultConfigurations = append(defaultConfigurations, timeoutConfig) + return defaultConfigurations, nil +} + +func (impl *timeoutClientImpl) getValueFromString(valueString string) (float64, int, error) { + // Convert string to float64 and ensure it's within integer range + valueFloat, err := strconv.ParseFloat(valueString, 64) + if err != nil { + return 0, 0, err + } + modifiedValue := math.Min(math.Floor(valueFloat), math.MaxInt64) + return modifiedValue, impl.getValueCount(modifiedValue), nil // Returning float64 for timeout +} + +func (impl *timeoutClientImpl) overrideInfraConfig(infraConfiguration *v1.InfraConfig, configurationBean *v1.ConfigurationBean) (*v1.InfraConfig, error) { + timeoutData, err := impl.getValueFromBean(configurationBean) + if err != nil { + return infraConfiguration, err + } + // if a user ever gives the timeout in float, after conversion to int64 it will be rounded off + timeUnit, ok := unitsBean.TimeUnitStr(configurationBean.Unit).GetUnit() + if !ok { + impl.logger.Errorw("error in getting time unit", "unit", configurationBean.Unit) + errMsg := errors.InvalidUnitFound(configurationBean.Unit, configurationBean.Key) + return infraConfiguration, util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + infraConfiguration = infraConfiguration.SetCiTimeout(timeoutData * timeUnit.ConversionFactor) + return infraConfiguration, nil +} + +func (impl *timeoutClientImpl) getValueFromBean(configurationBean *v1.ConfigurationBean) (float64, error) { + if configurationBean == nil { + return 0, nil + } + valueString, err := impl.formatTypedValueAsString(configurationBean.Value) + if err != nil { + return 0, err + } + timeoutData, _, err := impl.getValueFromString(valueString) + if err != nil { + impl.logger.Errorw("error in getting configMap data", "error", err, "configMap", configurationBean) + return 0, err + } + return timeoutData, nil +} + +func (impl *timeoutClientImpl) formatTypedValueAsString(configValue any) (string, error) { + var valueFloat float64 + switch v := configValue.(type) { + case float64: + valueFloat = v + default: + errMsg := fmt.Sprintf("invalid value for timeout configuration: %v", configValue) + return "", util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + //valueFloat, _ := strconv.ParseFloat(configValue, 64) + modifiedValue := math.Min(math.Floor(valueFloat), math.MaxInt64) + return strconv.FormatFloat(modifiedValue, 'f', -1, 64), nil +} + +func (impl *timeoutClientImpl) getValueCount(value float64) int { + if reflect.ValueOf(value).IsZero() { + return 0 + } + return 1 +} + +func (impl *timeoutClientImpl) handlePostCreateOperations(tx *pg.Tx, createdInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *timeoutClientImpl) handlePostUpdateOperations(tx *pg.Tx, updatedInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *timeoutClientImpl) handlePostDeleteOperations(tx *pg.Tx, deletedInfraConfig *repository.InfraProfileConfigurationEntity) error { + return nil +} + +func (impl *timeoutClientImpl) handleInfraConfigTriggerAudit(workflowId int, triggeredBy int32, infraConfig *v1.InfraConfig) error { + return nil +} + +func (impl *timeoutClientImpl) resolveScopeVariablesForAppliedConfiguration(scope resourceQualifiers.Scope, configuration *v1.ConfigurationBean) (*v1.ConfigurationBean, map[string]string, error) { + return configuration, nil, nil +} diff --git a/pkg/infraConfig/errors/errors.go b/pkg/infraConfig/errors/errors.go new file mode 100644 index 0000000000..0db507b445 --- /dev/null +++ b/pkg/infraConfig/errors/errors.go @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package errors + +import ( + "errors" + "fmt" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" +) + +const CPULimReqErrorCompErr = "cpu limit should not be less than cpu request" + +const MEMLimReqErrorCompErr = "memory limit should not be less than memory request" + +var NoPropertiesFoundError = errors.New("no properties found") + +var ProfileIdsRequired = errors.New("profile ids cannot be empty") + +const ( + PayloadValidationError = "payload validation failed" + InvalidProfileName = "profile name is invalid" + ProfileDoNotExists = "profile does not exist" + InvalidProfileNameChangeRequested = "invalid profile name change requested" + ProfileAlreadyExistsErr = "profile already exists" + DeletionBlockedForDefaultPlatform = "cannot delete default platform configuration" + UpdatableConfigurationFoundErr = "updatable configuration not belongs to platform" +) + +func InvalidUnitFound(unit string, key v1.ConfigKeyStr) string { + return fmt.Sprintf("invalid %q unit found for %q", unit, key) +} + +func ConfigurationMissingError(missingKey v1.ConfigKeyStr, profileName, platformName string) string { + return fmt.Sprintf("%q configuration missing in the %q profile %q platform", missingKey, profileName, platformName) +} diff --git a/pkg/infraConfig/repository/audit/infraConfigAuditRepository.go b/pkg/infraConfig/repository/audit/infraConfigAuditRepository.go new file mode 100644 index 0000000000..eacc68fd9e --- /dev/null +++ b/pkg/infraConfig/repository/audit/infraConfigAuditRepository.go @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package audit + +import ( + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/sql" + "github.com/go-pg/pg" +) + +type InfraConfigAuditRepository interface { + SaveInfraConfigHistorySnapshot(tx *pg.Tx, infraConfigTriggerHistories []*InfraConfigTriggerHistory) error +} + +type InfraConfigAuditRepositoryImpl struct { + dbConnection *pg.DB +} + +func NewInfraConfigAuditRepositoryImpl(dbConnection *pg.DB) *InfraConfigAuditRepositoryImpl { + return &InfraConfigAuditRepositoryImpl{ + dbConnection: dbConnection, + } +} + +type WorkflowType string + +const ( + CIWorkflowType WorkflowType = "CI" +) + +type InfraConfigTriggerHistory struct { + tableName struct{} `sql:"infra_config_trigger_history" pg:",discard_unknown_columns"` + Id int `sql:"id"` + Key v1.ConfigKey `sql:"key"` + ValueString string `sql:"value_string"` + Platform string `sql:"platform"` + WorkflowId int `sql:"workflow_id"` + WorkflowType WorkflowType `sql:"workflow_type"` + sql.AuditLog +} + +func (i *InfraConfigTriggerHistory) WithPlatform(platform string) *InfraConfigTriggerHistory { + i.Platform = platform + return i +} + +func (i *InfraConfigTriggerHistory) WithWorkflowId(workflowId int) *InfraConfigTriggerHistory { + i.WorkflowId = workflowId + return i +} + +func (i *InfraConfigTriggerHistory) WithWorkflowType(workflowType WorkflowType) *InfraConfigTriggerHistory { + i.WorkflowType = workflowType + return i +} + +func (i *InfraConfigTriggerHistory) WithAuditLog(userId int32) *InfraConfigTriggerHistory { + i.AuditLog = sql.NewDefaultAuditLog(userId) + return i +} + +func (impl *InfraConfigAuditRepositoryImpl) SaveInfraConfigHistorySnapshot(tx *pg.Tx, infraConfigTriggerHistories []*InfraConfigTriggerHistory) error { + if len(infraConfigTriggerHistories) == 0 { + return nil + } + _, err := tx.Model(&infraConfigTriggerHistories).Insert() + if err != nil { + return err + } + return nil +} diff --git a/pkg/infraConfig/repository/infraConfigRepository.go b/pkg/infraConfig/repository/infraConfigRepository.go index 1d32d6be1c..59c6a5f335 100644 --- a/pkg/infraConfig/repository/infraConfigRepository.go +++ b/pkg/infraConfig/repository/infraConfigRepository.go @@ -18,21 +18,27 @@ package repository import ( "fmt" - infraBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean" - "github.com/devtron-labs/devtron/pkg/infraConfig/units" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + errors2 "github.com/devtron-labs/devtron/pkg/infraConfig/errors" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" + "github.com/go-pg/pg/orm" "github.com/pkg/errors" - "time" ) +type ProfileIdentifierCount struct { + ProfileId int + IdentifierCount int +} + type InfraProfileEntity struct { - tableName struct{} `sql:"infra_profile" pg:",discard_unknown_columns"` - Id int `sql:"id"` - Name string `sql:"name"` - Description string `sql:"description"` - BuildxDriverType infraBean.BuildxDriver `sql:"buildx_driver_type,notnull"` - Active bool `sql:"active"` + tableName struct{} `sql:"infra_profile" pg:",discard_unknown_columns"` + Id int `sql:"id"` + Name string `sql:"name"` + Description string `sql:"description"` + BuildxDriverType v1.BuildxDriver `sql:"buildx_driver_type,notnull"` + Active bool `sql:"active"` sql.AuditLog } @@ -51,15 +57,16 @@ func GetUniqueId(profileId int, platform string) string { } type InfraProfileConfigurationEntity struct { - tableName struct{} `sql:"infra_profile_configuration" pg:",discard_unknown_columns"` - Id int `sql:"id,pk"` - Key infraBean.ConfigKey `sql:"key,notnull"` - Value float64 `sql:"value"` - ValueString string `sql:"value_string,notnull"` - Unit units.UnitSuffix `sql:"unit,notnull"` - ProfilePlatformMappingId int `sql:"profile_platform_mapping_id"` - Active bool `sql:"active,notnull"` - UniqueId string `sql:"-"` + tableName struct{} `sql:"infra_profile_configuration" pg:",discard_unknown_columns"` + Id int `sql:"id,pk"` + Key v1.ConfigKey `sql:"key,notnull"` + // Deprecated; use ValueString instead + Value float64 `sql:"value"` + ValueString string `sql:"value_string,notnull"` + Unit unitsBean.UnitType `sql:"unit,notnull"` + ProfilePlatformMappingId int `sql:"profile_platform_mapping_id"` + Active bool `sql:"active,notnull"` + UniqueId string `sql:"-"` // Deprecated; use ProfilePlatformMappingId ProfileId int `sql:"profile_id"` @@ -69,9 +76,9 @@ type InfraProfileConfigurationEntity struct { type InfraConfigRepository interface { GetProfileByName(name string) (*InfraProfileEntity, error) + CheckIfProfileExistsByName(name string) (bool, error) GetConfigurationsByProfileName(profileName string) ([]*InfraProfileConfigurationEntity, error) - GetConfigurationsByProfileIds(profileIds []int) ([]*InfraProfileConfigurationEntity, error) - GetPlatformsByProfileName(profileName string) ([]*ProfilePlatformMapping, error) + GetConfigurationsByProfileId(profileId int) ([]*InfraProfileConfigurationEntity, error) CreatePlatformProfileMapping(tx *pg.Tx, platformMapping []*ProfilePlatformMapping) error @@ -80,7 +87,18 @@ type InfraConfigRepository interface { UpdateConfigurations(tx *pg.Tx, configurations []*InfraProfileConfigurationEntity) error UpdateProfile(tx *pg.Tx, profileName string, profile *InfraProfileEntity) error + + // GetProfileListByIds returns the list of profiles for the given profileIds + // includeDefault is used to explicitly include the default profile in the list + GetProfileListByIds(profileIds []int, includeDefault bool) ([]*InfraProfileEntity, error) + GetConfigurationsByProfileIds(profileIds []int) ([]*InfraProfileConfigurationEntity, error) + UpdatePlatformProfileMapping(tx *pg.Tx, platformMappings []*ProfilePlatformMapping) error + GetPlatformListByProfileId(profileId int) ([]string, error) + GetPlatformsByProfileName(profileName string) ([]*ProfilePlatformMapping, error) + GetPlatformsByProfileIds(profileIds []int) ([]*ProfilePlatformMapping, error) + GetPlatformsByProfileById(profileId int) ([]*ProfilePlatformMapping, error) sql.TransactionWrapper + InfraConfigRepositoryEnt } type InfraConfigRepositoryImpl struct { @@ -102,6 +120,11 @@ func (impl *InfraConfigRepositoryImpl) CreateProfile(tx *pg.Tx, infraProfile *In return err } +func (impl *InfraConfigRepositoryImpl) CreatePlatformProfileMapping(tx *pg.Tx, platformMapping []*ProfilePlatformMapping) error { + err := tx.Insert(&platformMapping) + return err +} + func (impl *InfraConfigRepositoryImpl) GetProfileByName(name string) (*InfraProfileEntity, error) { infraProfile := &InfraProfileEntity{} err := impl.dbConnection.Model(infraProfile). @@ -111,6 +134,11 @@ func (impl *InfraConfigRepositoryImpl) GetProfileByName(name string) (*InfraProf return infraProfile, err } +func (impl *InfraConfigRepositoryImpl) CheckIfProfileExistsByName(name string) (bool, error) { + infraProfile := &InfraProfileEntity{} + return impl.dbConnection.Model(infraProfile).Where("name = ?", name).Where("active =?", true).Exists() +} + func (impl *InfraConfigRepositoryImpl) CreateConfigurations(tx *pg.Tx, configurations []*InfraProfileConfigurationEntity) error { if len(configurations) == 0 { return nil @@ -137,12 +165,31 @@ func (impl *InfraConfigRepositoryImpl) GetConfigurationsByProfileName(profileNam Where("infra_profile_configuration_entity.active = ?", true). Select() if errors.Is(err, pg.ErrNoRows) { - return nil, errors.New(infraBean.NO_PROPERTIES_FOUND) + return nil, errors2.NoPropertiesFoundError + } + return configurations, err +} + +func (impl *InfraConfigRepositoryImpl) GetConfigurationsByProfileId(profileId int) ([]*InfraProfileConfigurationEntity, error) { + var configurations []*InfraProfileConfigurationEntity + err := impl.dbConnection.Model(&configurations). + Column("infra_profile_configuration_entity.*", "ProfilePlatformMapping"). + Join("INNER JOIN infra_profile"). + JoinOn("infra_profile_configuration_entity.profile_id = infra_profile.id"). + Where("infra_profile.id = ?", profileId). + Where("infra_profile.active = ?", true). + Where("infra_profile_configuration_entity.active = ?", true). + Select() + if errors.Is(err, pg.ErrNoRows) { + return nil, errors2.NoPropertiesFoundError } return configurations, err } func (impl *InfraConfigRepositoryImpl) GetConfigurationsByProfileIds(profileIds []int) ([]*InfraProfileConfigurationEntity, error) { + if len(profileIds) == 0 { + return nil, errors2.ProfileIdsRequired + } var configurations []*InfraProfileConfigurationEntity err := impl.dbConnection.Model(&configurations). Column("infra_profile_configuration_entity.*", "ProfilePlatformMapping"). @@ -151,7 +198,7 @@ func (impl *InfraConfigRepositoryImpl) GetConfigurationsByProfileIds(profileIds Where("infra_profile_configuration_entity.active = ?", true). Select() if errors.Is(err, pg.ErrNoRows) { - return nil, errors.New(infraBean.NO_PROPERTIES_FOUND) + return nil, errors2.NoPropertiesFoundError } return configurations, err } @@ -164,19 +211,47 @@ func (impl *InfraConfigRepositoryImpl) UpdateProfile(tx *pg.Tx, profileName stri Set("updated_by = ?", profile.UpdatedBy). Set("updated_on = ?", profile.UpdatedOn). Where("name = ?", profileName). - Where("active = ?", true). Update() return err } -func (impl *InfraConfigRepositoryImpl) UpdateBuildxDriverTypeInAllProfiles(tx *pg.Tx, buildxDriverType infraBean.BuildxDriver) error { - _, err := tx.Model((*InfraProfileEntity)(nil)). - Set("buildx_driver_type = ?", buildxDriverType). - Set("updated_by = ?", 1). - Set("updated_on = ?", time.Now()). +func (impl *InfraConfigRepositoryImpl) GetProfileListByIds(profileIds []int, includeDefault bool) ([]*InfraProfileEntity, error) { + var infraProfiles []*InfraProfileEntity + err := impl.dbConnection.Model(&infraProfiles). Where("active = ?", true). - Update() - return err + WhereGroup(func(q *orm.Query) (*orm.Query, error) { + if len(profileIds) != 0 { + q = q.WhereOr("id IN (?)", pg.In(profileIds)) + } + if includeDefault { + q = q.WhereOr("name = ?", v1.GLOBAL_PROFILE_NAME) + } + return q, nil + }).Select() + return infraProfiles, err +} + +func (impl *InfraConfigRepositoryImpl) GetPlatformListByProfileId(profileId int) ([]string, error) { + var platforms []string + err := impl.dbConnection.Model(&ProfilePlatformMapping{}). + Column("platform"). + Where("profile_id = ?", profileId). + Where("active = ?", true). + Select(&platforms) + return platforms, err +} + +func (impl *InfraConfigRepositoryImpl) GetPlatformsByProfileIds(profileIds []int) ([]*ProfilePlatformMapping, error) { + var profilePlatformMappings []*ProfilePlatformMapping + err := impl.dbConnection.Model(&profilePlatformMappings). + Where("active = ?", true). + WhereGroup(func(q *orm.Query) (*orm.Query, error) { + if len(profileIds) > 0 { + q = q.WhereOr("profile_id IN (?)", pg.In(profileIds)) + } + return q, nil + }).Select() + return profilePlatformMappings, err } func (impl *InfraConfigRepositoryImpl) GetPlatformsByProfileName(profileName string) ([]*ProfilePlatformMapping, error) { @@ -190,7 +265,32 @@ func (impl *InfraConfigRepositoryImpl) GetPlatformsByProfileName(profileName str Select() return profilePlatformMappings, err } -func (impl *InfraConfigRepositoryImpl) CreatePlatformProfileMapping(tx *pg.Tx, platformMapping []*ProfilePlatformMapping) error { - err := tx.Insert(&platformMapping) - return err + +func (impl *InfraConfigRepositoryImpl) UpdatePlatformProfileMapping(tx *pg.Tx, platformMappings []*ProfilePlatformMapping) error { + var err error + for _, platformMapping := range platformMappings { + _, err = tx.Model(platformMapping). + Set("platform = ?", platformMapping.Platform). + Set("active = ?", platformMapping.Active). + Set("updated_by = ?", platformMapping.UpdatedBy). + Set("updated_on = ?", platformMapping.UpdatedOn). + Where("id = ?", platformMapping.Id). + Update() + if err != nil { + return err + } + } + return nil +} + +func (impl *InfraConfigRepositoryImpl) GetPlatformsByProfileById(profileId int) ([]*ProfilePlatformMapping, error) { + var profilePlatformMappings []*ProfilePlatformMapping + err := impl.dbConnection.Model(&profilePlatformMappings). + Column("profile_platform_mapping.*"). + Join("INNER JOIN infra_profile ip ON profile_platform_mapping.profile_id = ip.id"). + Where("ip.id = ?", profileId). + Where("ip.active = ?", true). + Where("profile_platform_mapping.active = ?", true). + Select() + return profilePlatformMappings, err } diff --git a/pkg/infraConfig/repository/infraConfigRepository_ent.go b/pkg/infraConfig/repository/infraConfigRepository_ent.go new file mode 100644 index 0000000000..70cd3458f8 --- /dev/null +++ b/pkg/infraConfig/repository/infraConfigRepository_ent.go @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package repository + +type InfraConfigRepositoryEnt interface { +} diff --git a/pkg/infraConfig/repository/mocks/InfraConfigRepository.go b/pkg/infraConfig/repository/mocks/InfraConfigRepository.go new file mode 100644 index 0000000000..0dba7e7a0d --- /dev/null +++ b/pkg/infraConfig/repository/mocks/InfraConfigRepository.go @@ -0,0 +1,813 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import ( + pg "github.com/go-pg/pg" + mock "github.com/stretchr/testify/mock" + + repository "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + + v1 "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" +) + +// InfraConfigRepository is an autogenerated mock type for the InfraConfigRepository type +type InfraConfigRepository struct { + mock.Mock +} + +// CheckIfProfileExistsByName provides a mock function with given fields: name +func (_m *InfraConfigRepository) CheckIfProfileExistsByName(name string) (bool, error) { + ret := _m.Called(name) + + if len(ret) == 0 { + panic("no return value specified for CheckIfProfileExistsByName") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(string) (bool, error)); ok { + return rf(name) + } + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(name) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CommitTx provides a mock function with given fields: tx +func (_m *InfraConfigRepository) CommitTx(tx *pg.Tx) error { + ret := _m.Called(tx) + + if len(ret) == 0 { + panic("no return value specified for CommitTx") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx) error); ok { + r0 = rf(tx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreateConfigurations provides a mock function with given fields: tx, configurations +func (_m *InfraConfigRepository) CreateConfigurations(tx *pg.Tx, configurations []*repository.InfraProfileConfigurationEntity) error { + ret := _m.Called(tx, configurations) + + if len(ret) == 0 { + panic("no return value specified for CreateConfigurations") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, []*repository.InfraProfileConfigurationEntity) error); ok { + r0 = rf(tx, configurations) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreatePlatformProfileMapping provides a mock function with given fields: tx, platformMapping +func (_m *InfraConfigRepository) CreatePlatformProfileMapping(tx *pg.Tx, platformMapping []*repository.ProfilePlatformMapping) error { + ret := _m.Called(tx, platformMapping) + + if len(ret) == 0 { + panic("no return value specified for CreatePlatformProfileMapping") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, []*repository.ProfilePlatformMapping) error); ok { + r0 = rf(tx, platformMapping) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreateProfile provides a mock function with given fields: tx, infraProfile +func (_m *InfraConfigRepository) CreateProfile(tx *pg.Tx, infraProfile *repository.InfraProfileEntity) error { + ret := _m.Called(tx, infraProfile) + + if len(ret) == 0 { + panic("no return value specified for CreateProfile") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, *repository.InfraProfileEntity) error); ok { + r0 = rf(tx, infraProfile) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteConfigurations provides a mock function with given fields: tx, profileId +func (_m *InfraConfigRepository) DeleteConfigurations(tx *pg.Tx, profileId int) error { + ret := _m.Called(tx, profileId) + + if len(ret) == 0 { + panic("no return value specified for DeleteConfigurations") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, int) error); ok { + r0 = rf(tx, profileId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteProfile provides a mock function with given fields: tx, id +func (_m *InfraConfigRepository) DeleteProfile(tx *pg.Tx, id int) error { + ret := _m.Called(tx, id) + + if len(ret) == 0 { + panic("no return value specified for DeleteProfile") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, int) error); ok { + r0 = rf(tx, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteProfilePlatformMapping provides a mock function with given fields: tx, profileId +func (_m *InfraConfigRepository) DeleteProfilePlatformMapping(tx *pg.Tx, profileId int) error { + ret := _m.Called(tx, profileId) + + if len(ret) == 0 { + panic("no return value specified for DeleteProfilePlatformMapping") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, int) error); ok { + r0 = rf(tx, profileId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetActiveProfileNames provides a mock function with given fields: +func (_m *InfraConfigRepository) GetActiveProfileNames() ([]string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetActiveProfileNames") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func() ([]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetActiveUniquePlatformNames provides a mock function with given fields: +func (_m *InfraConfigRepository) GetActiveUniquePlatformNames() ([]string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetActiveUniquePlatformNames") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func() ([]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetAllActiveProfilesIds provides a mock function with given fields: +func (_m *InfraConfigRepository) GetAllActiveProfilesIds() ([]int, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetAllActiveProfilesIds") + } + + var r0 []int + var r1 error + if rf, ok := ret.Get(0).(func() ([]int, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []int); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]int) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetConfigurationsByProfileId provides a mock function with given fields: profileId +func (_m *InfraConfigRepository) GetConfigurationsByProfileId(profileId int) ([]*repository.InfraProfileConfigurationEntity, error) { + ret := _m.Called(profileId) + + if len(ret) == 0 { + panic("no return value specified for GetConfigurationsByProfileId") + } + + var r0 []*repository.InfraProfileConfigurationEntity + var r1 error + if rf, ok := ret.Get(0).(func(int) ([]*repository.InfraProfileConfigurationEntity, error)); ok { + return rf(profileId) + } + if rf, ok := ret.Get(0).(func(int) []*repository.InfraProfileConfigurationEntity); ok { + r0 = rf(profileId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*repository.InfraProfileConfigurationEntity) + } + } + + if rf, ok := ret.Get(1).(func(int) error); ok { + r1 = rf(profileId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetConfigurationsByProfileIds provides a mock function with given fields: profileIds +func (_m *InfraConfigRepository) GetConfigurationsByProfileIds(profileIds []int) ([]*repository.InfraProfileConfigurationEntity, error) { + ret := _m.Called(profileIds) + + if len(ret) == 0 { + panic("no return value specified for GetConfigurationsByProfileIds") + } + + var r0 []*repository.InfraProfileConfigurationEntity + var r1 error + if rf, ok := ret.Get(0).(func([]int) ([]*repository.InfraProfileConfigurationEntity, error)); ok { + return rf(profileIds) + } + if rf, ok := ret.Get(0).(func([]int) []*repository.InfraProfileConfigurationEntity); ok { + r0 = rf(profileIds) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*repository.InfraProfileConfigurationEntity) + } + } + + if rf, ok := ret.Get(1).(func([]int) error); ok { + r1 = rf(profileIds) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetConfigurationsByProfileName provides a mock function with given fields: profileName +func (_m *InfraConfigRepository) GetConfigurationsByProfileName(profileName string) ([]*repository.InfraProfileConfigurationEntity, error) { + ret := _m.Called(profileName) + + if len(ret) == 0 { + panic("no return value specified for GetConfigurationsByProfileName") + } + + var r0 []*repository.InfraProfileConfigurationEntity + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]*repository.InfraProfileConfigurationEntity, error)); ok { + return rf(profileName) + } + if rf, ok := ret.Get(0).(func(string) []*repository.InfraProfileConfigurationEntity); ok { + r0 = rf(profileName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*repository.InfraProfileConfigurationEntity) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(profileName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetPlatformListByProfileId provides a mock function with given fields: profileId +func (_m *InfraConfigRepository) GetPlatformListByProfileId(profileId int) ([]string, error) { + ret := _m.Called(profileId) + + if len(ret) == 0 { + panic("no return value specified for GetPlatformListByProfileId") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(int) ([]string, error)); ok { + return rf(profileId) + } + if rf, ok := ret.Get(0).(func(int) []string); ok { + r0 = rf(profileId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(int) error); ok { + r1 = rf(profileId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetPlatformsByProfileById provides a mock function with given fields: profileId +func (_m *InfraConfigRepository) GetPlatformsByProfileById(profileId int) ([]*repository.ProfilePlatformMapping, error) { + ret := _m.Called(profileId) + + if len(ret) == 0 { + panic("no return value specified for GetPlatformsByProfileById") + } + + var r0 []*repository.ProfilePlatformMapping + var r1 error + if rf, ok := ret.Get(0).(func(int) ([]*repository.ProfilePlatformMapping, error)); ok { + return rf(profileId) + } + if rf, ok := ret.Get(0).(func(int) []*repository.ProfilePlatformMapping); ok { + r0 = rf(profileId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*repository.ProfilePlatformMapping) + } + } + + if rf, ok := ret.Get(1).(func(int) error); ok { + r1 = rf(profileId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetPlatformsByProfileIds provides a mock function with given fields: profileIds +func (_m *InfraConfigRepository) GetPlatformsByProfileIds(profileIds []int) ([]*repository.ProfilePlatformMapping, error) { + ret := _m.Called(profileIds) + + if len(ret) == 0 { + panic("no return value specified for GetPlatformsByProfileIds") + } + + var r0 []*repository.ProfilePlatformMapping + var r1 error + if rf, ok := ret.Get(0).(func([]int) ([]*repository.ProfilePlatformMapping, error)); ok { + return rf(profileIds) + } + if rf, ok := ret.Get(0).(func([]int) []*repository.ProfilePlatformMapping); ok { + r0 = rf(profileIds) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*repository.ProfilePlatformMapping) + } + } + + if rf, ok := ret.Get(1).(func([]int) error); ok { + r1 = rf(profileIds) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetPlatformsByProfileName provides a mock function with given fields: profileName +func (_m *InfraConfigRepository) GetPlatformsByProfileName(profileName string) ([]*repository.ProfilePlatformMapping, error) { + ret := _m.Called(profileName) + + if len(ret) == 0 { + panic("no return value specified for GetPlatformsByProfileName") + } + + var r0 []*repository.ProfilePlatformMapping + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]*repository.ProfilePlatformMapping, error)); ok { + return rf(profileName) + } + if rf, ok := ret.Get(0).(func(string) []*repository.ProfilePlatformMapping); ok { + r0 = rf(profileName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*repository.ProfilePlatformMapping) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(profileName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetProfileById provides a mock function with given fields: profileId +func (_m *InfraConfigRepository) GetProfileById(profileId int) (*repository.InfraProfileEntity, error) { + ret := _m.Called(profileId) + + if len(ret) == 0 { + panic("no return value specified for GetProfileById") + } + + var r0 *repository.InfraProfileEntity + var r1 error + if rf, ok := ret.Get(0).(func(int) (*repository.InfraProfileEntity, error)); ok { + return rf(profileId) + } + if rf, ok := ret.Get(0).(func(int) *repository.InfraProfileEntity); ok { + r0 = rf(profileId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*repository.InfraProfileEntity) + } + } + + if rf, ok := ret.Get(1).(func(int) error); ok { + r1 = rf(profileId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetProfileByName provides a mock function with given fields: name +func (_m *InfraConfigRepository) GetProfileByName(name string) (*repository.InfraProfileEntity, error) { + ret := _m.Called(name) + + if len(ret) == 0 { + panic("no return value specified for GetProfileByName") + } + + var r0 *repository.InfraProfileEntity + var r1 error + if rf, ok := ret.Get(0).(func(string) (*repository.InfraProfileEntity, error)); ok { + return rf(name) + } + if rf, ok := ret.Get(0).(func(string) *repository.InfraProfileEntity); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*repository.InfraProfileEntity) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetProfileIdByName provides a mock function with given fields: name +func (_m *InfraConfigRepository) GetProfileIdByName(name string) (int, error) { + ret := _m.Called(name) + + if len(ret) == 0 { + panic("no return value specified for GetProfileIdByName") + } + + var r0 int + var r1 error + if rf, ok := ret.Get(0).(func(string) (int, error)); ok { + return rf(name) + } + if rf, ok := ret.Get(0).(func(string) int); ok { + r0 = rf(name) + } else { + r0 = ret.Get(0).(int) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetProfileList provides a mock function with given fields: profileNameLike +func (_m *InfraConfigRepository) GetProfileList(profileNameLike string) ([]*repository.InfraProfileEntity, error) { + ret := _m.Called(profileNameLike) + + if len(ret) == 0 { + panic("no return value specified for GetProfileList") + } + + var r0 []*repository.InfraProfileEntity + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]*repository.InfraProfileEntity, error)); ok { + return rf(profileNameLike) + } + if rf, ok := ret.Get(0).(func(string) []*repository.InfraProfileEntity); ok { + r0 = rf(profileNameLike) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*repository.InfraProfileEntity) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(profileNameLike) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetProfileListByIds provides a mock function with given fields: profileIds, includeDefault +func (_m *InfraConfigRepository) GetProfileListByIds(profileIds []int, includeDefault bool) ([]*repository.InfraProfileEntity, error) { + ret := _m.Called(profileIds, includeDefault) + + if len(ret) == 0 { + panic("no return value specified for GetProfileListByIds") + } + + var r0 []*repository.InfraProfileEntity + var r1 error + if rf, ok := ret.Get(0).(func([]int, bool) ([]*repository.InfraProfileEntity, error)); ok { + return rf(profileIds, includeDefault) + } + if rf, ok := ret.Get(0).(func([]int, bool) []*repository.InfraProfileEntity); ok { + r0 = rf(profileIds, includeDefault) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*repository.InfraProfileEntity) + } + } + + if rf, ok := ret.Get(1).(func([]int, bool) error); ok { + r1 = rf(profileIds, includeDefault) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetProfilesWhichContainsAllDefaultConfigurationKeysUsingProfileName provides a mock function with given fields: +func (_m *InfraConfigRepository) GetProfilesWhichContainsAllDefaultConfigurationKeysUsingProfileName() ([]int, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetProfilesWhichContainsAllDefaultConfigurationKeysUsingProfileName") + } + + var r0 []int + var r1 error + if rf, ok := ret.Get(0).(func() ([]int, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []int); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]int) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetProfilesWhichContainsAllDefaultConfigurationKeysWithProfileId provides a mock function with given fields: defaultProfileId +func (_m *InfraConfigRepository) GetProfilesWhichContainsAllDefaultConfigurationKeysWithProfileId(defaultProfileId int) ([]int, error) { + ret := _m.Called(defaultProfileId) + + if len(ret) == 0 { + panic("no return value specified for GetProfilesWhichContainsAllDefaultConfigurationKeysWithProfileId") + } + + var r0 []int + var r1 error + if rf, ok := ret.Get(0).(func(int) ([]int, error)); ok { + return rf(defaultProfileId) + } + if rf, ok := ret.Get(0).(func(int) []int); ok { + r0 = rf(defaultProfileId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]int) + } + } + + if rf, ok := ret.Get(1).(func(int) error); ok { + r1 = rf(defaultProfileId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RollbackTx provides a mock function with given fields: tx +func (_m *InfraConfigRepository) RollbackTx(tx *pg.Tx) error { + ret := _m.Called(tx) + + if len(ret) == 0 { + panic("no return value specified for RollbackTx") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx) error); ok { + r0 = rf(tx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// StartTx provides a mock function with given fields: +func (_m *InfraConfigRepository) StartTx() (*pg.Tx, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for StartTx") + } + + var r0 *pg.Tx + var r1 error + if rf, ok := ret.Get(0).(func() (*pg.Tx, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *pg.Tx); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*pg.Tx) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdateBuildxDriverTypeInAllProfiles provides a mock function with given fields: tx, buildxDriverType +func (_m *InfraConfigRepository) UpdateBuildxDriverTypeInAllProfiles(tx *pg.Tx, buildxDriverType v1.BuildxDriver) error { + ret := _m.Called(tx, buildxDriverType) + + if len(ret) == 0 { + panic("no return value specified for UpdateBuildxDriverTypeInAllProfiles") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, v1.BuildxDriver) error); ok { + r0 = rf(tx, buildxDriverType) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateConfigurations provides a mock function with given fields: tx, configurations +func (_m *InfraConfigRepository) UpdateConfigurations(tx *pg.Tx, configurations []*repository.InfraProfileConfigurationEntity) error { + ret := _m.Called(tx, configurations) + + if len(ret) == 0 { + panic("no return value specified for UpdateConfigurations") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, []*repository.InfraProfileConfigurationEntity) error); ok { + r0 = rf(tx, configurations) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdatePlatformProfileMapping provides a mock function with given fields: tx, platformMappings +func (_m *InfraConfigRepository) UpdatePlatformProfileMapping(tx *pg.Tx, platformMappings []*repository.ProfilePlatformMapping) error { + ret := _m.Called(tx, platformMappings) + + if len(ret) == 0 { + panic("no return value specified for UpdatePlatformProfileMapping") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, []*repository.ProfilePlatformMapping) error); ok { + r0 = rf(tx, platformMappings) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateProfile provides a mock function with given fields: tx, profileName, profile +func (_m *InfraConfigRepository) UpdateProfile(tx *pg.Tx, profileName string, profile *repository.InfraProfileEntity) error { + ret := _m.Called(tx, profileName, profile) + + if len(ret) == 0 { + panic("no return value specified for UpdateProfile") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*pg.Tx, string, *repository.InfraProfileEntity) error); ok { + r0 = rf(tx, profileName, profile) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewInfraConfigRepository creates a new instance of InfraConfigRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewInfraConfigRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *InfraConfigRepository { + mock := &InfraConfigRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/infraConfig/service/audit/infraConfigAudit.go b/pkg/infraConfig/service/audit/infraConfigAudit.go new file mode 100644 index 0000000000..c6263b9b44 --- /dev/null +++ b/pkg/infraConfig/service/audit/infraConfigAudit.go @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package audit + +import ( + audit2 "github.com/devtron-labs/devtron/pkg/infraConfig/adapter/audit" + infraBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository/audit" + "github.com/devtron-labs/devtron/pkg/sql" + "github.com/go-pg/pg" + "go.uber.org/zap" +) + +type InfraConfigAuditService interface { + SaveCiInfraConfigHistorySnapshot(tx *pg.Tx, workflowId int, triggeredBy int32, infraConfigs map[string]*infraBean.InfraConfig) error + sql.TransactionWrapper +} + +type InfraConfigAuditServiceImpl struct { + logger *zap.SugaredLogger + infraConfigAuditRepository audit.InfraConfigAuditRepository + *sql.TransactionUtilImpl +} + +func NewInfraConfigAuditServiceImpl(logger *zap.SugaredLogger, + infraConfigAuditRepository audit.InfraConfigAuditRepository, + transactionUtilImpl *sql.TransactionUtilImpl) *InfraConfigAuditServiceImpl { + return &InfraConfigAuditServiceImpl{ + logger: logger, + infraConfigAuditRepository: infraConfigAuditRepository, + TransactionUtilImpl: transactionUtilImpl, + } +} + +func (impl *InfraConfigAuditServiceImpl) SaveCiInfraConfigHistorySnapshot(tx *pg.Tx, + workflowId int, triggeredBy int32, infraConfigs map[string]*infraBean.InfraConfig) error { + infraConfigTriggerAudits := make([]*audit.InfraConfigTriggerHistory, 0) + for platform, infraConfig := range infraConfigs { + infraConfigTriggerHistories, err := audit2.GetInfraConfigTriggerAudit(infraConfig) + if err != nil { + impl.logger.Errorw("failed to get infra config trigger audit", "error", err, "infraConfig", infraConfig) + return err + } + for _, infraConfigTriggerHistory := range infraConfigTriggerHistories { + infraConfigTriggerHistory = infraConfigTriggerHistory. + WithPlatform(platform).WithWorkflowId(workflowId). + WithWorkflowType(audit.CIWorkflowType).WithAuditLog(triggeredBy) + } + infraConfigTriggerAudits = append(infraConfigTriggerAudits, infraConfigTriggerHistories...) + } + impl.logger.Debugw("saving infra config history snapshot", "workflowId", workflowId, + "infraConfigs", infraConfigs, "infraConfigTriggerAudits", infraConfigTriggerAudits) + err := impl.infraConfigAuditRepository.SaveInfraConfigHistorySnapshot(tx, infraConfigTriggerAudits) + if err != nil { + impl.logger.Errorw("failed to save infra config history snapshot", "error", err, "infraConfigTriggerAudits", infraConfigTriggerAudits) + return err + } + return nil +} diff --git a/pkg/infraConfig/service/configurationValidator.go b/pkg/infraConfig/service/configurationValidator.go deleted file mode 100644 index 2f088e28f3..0000000000 --- a/pkg/infraConfig/service/configurationValidator.go +++ /dev/null @@ -1,187 +0,0 @@ -package service - -import ( - "fmt" - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" - "github.com/devtron-labs/devtron/pkg/infraConfig/units" - "github.com/devtron-labs/devtron/pkg/infraConfig/util" - "github.com/pkg/errors" -) - -func (impl *InfraConfigServiceImpl) validateInfraConfig(profileBean *bean.ProfileBeanDto, defaultProfile *bean.ProfileBeanDto) error { - err := utils.ValidatePayloadConfig(profileBean) - if err != nil { - return err - } - if profileBean.Name == bean.GLOBAL_PROFILE_NAME || profileBean.Name == bean.DEFAULT_PROFILE_NAME { - for platform, configurations := range profileBean.Configurations { - // Create a copy of the defaultConfigKeysMap to track missing keys - missingKeysMap := utils.GetDefaultConfigKeysMap() - // Mark the keys that are present - for _, config := range configurations { - if _, exists := missingKeysMap[config.Key]; exists && config.Active { - missingKeysMap[config.Key] = false - } - } - - // Check if any default keys are still true (missing) - var missingKeys []bean.ConfigKeyStr - for key, isMissing := range missingKeysMap { - if isMissing && platform != bean.RUNNER_PLATFORM && key != bean.TIME_OUT { - missingKeys = append(missingKeys, key) - } - if isMissing && platform == bean.RUNNER_PLATFORM { - missingKeys = append(missingKeys, key) - } - } - - if len(missingKeys) > 0 { - impl.logger.Errorw("Missing default configuration keys for platform", "platform", platform, "missingKeys", missingKeys, "profileName", profileBean.Name) - err = errors.New(bean.ConfigurationMissingInGlobalPlatform) - return err - } - } - } - // currently validating cpu and memory limits and reqs only - var ( - cpuLimit *bean.ConfigurationBean - cpuReq *bean.ConfigurationBean - memLimit *bean.ConfigurationBean - memReq *bean.ConfigurationBean - timeout *bean.ConfigurationBean - ) - - for _, platformConfigurations := range profileBean.Configurations { - for _, configuration := range platformConfigurations { - // get cpu limit and req - switch configuration.Key { - case bean.CPU_LIMIT: - cpuLimit = configuration - case bean.CPU_REQUEST: - cpuReq = configuration - case bean.MEMORY_LIMIT: - memLimit = configuration - case bean.MEMORY_REQUEST: - memReq = configuration - case bean.TIME_OUT: - timeout = configuration - } - } - } - - // validate cpu - err = impl.validateCPU(cpuLimit, cpuReq) - if err != nil { - return err - } - // validate mem - err = impl.validateMEM(memLimit, memReq) - if err != nil { - return err - } - - err = impl.validateTimeOut(timeout) - if err != nil { - return err - } - return nil -} -func (impl *InfraConfigServiceImpl) validateCPU(cpuLimit, cpuReq *bean.ConfigurationBean) error { - cpuLimitUnitSuffix := units.CPUUnitStr(cpuLimit.Unit) - cpuReqUnitSuffix := units.CPUUnitStr(cpuReq.Unit) - cpuUnits := impl.units.GetCpuUnits() - cpuLimitUnit, ok := cpuUnits[cpuLimitUnitSuffix] - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidUnit, cpuLimit.Unit, cpuLimit.Key)) - } - cpuReqUnit, ok := cpuUnits[cpuReqUnitSuffix] - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidUnit, cpuReq.Unit, cpuReq.Key)) - } - - cpuLimitInterfaceVal, err := utils.GetTypedValue(cpuLimit.Key, cpuLimit.Value) - if err != nil { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, cpuLimit.Key, cpuLimit.Value)) - } - cpuLimitVal, ok := cpuLimitInterfaceVal.(float64) - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, cpuLimit.Key, cpuLimit.Value)) - } - - cpuReqInterfaceVal, err := utils.GetTypedValue(cpuReq.Key, cpuReq.Value) - if err != nil { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, cpuReq.Key, cpuReq.Value)) - } - cpuReqVal, ok := cpuReqInterfaceVal.(float64) - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, cpuReq.Key, cpuReq.Value)) - } - if !validLimReq(cpuLimitVal, cpuLimitUnit.ConversionFactor, cpuReqVal, cpuReqUnit.ConversionFactor) { - return errors.New(bean.CPULimReqErrorCompErr) - } - return nil -} -func (impl *InfraConfigServiceImpl) validateTimeOut(timeOut *bean.ConfigurationBean) error { - if timeOut == nil { - return nil - } - timeoutUnitSuffix := units.TimeUnitStr(timeOut.Unit) - timeUnits := impl.units.GetTimeUnits() - _, ok := timeUnits[timeoutUnitSuffix] - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidUnit, timeOut.Unit, timeOut.Key)) - } - timeout, err := utils.GetTypedValue(timeOut.Key, timeOut.Value) - if err != nil { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, timeOut.Key, timeOut.Value)) - } - _, ok = timeout.(float64) - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, timeOut.Key, timeOut.Value)) - } - return nil -} -func (impl *InfraConfigServiceImpl) validateMEM(memLimit, memReq *bean.ConfigurationBean) error { - memLimitUnitSuffix := units.MemoryUnitStr(memLimit.Unit) - memReqUnitSuffix := units.MemoryUnitStr(memReq.Unit) - memUnits := impl.units.GetMemoryUnits() - memLimitUnit, ok := memUnits[memLimitUnitSuffix] - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidUnit, memLimit.Unit, memLimit.Key)) - } - memReqUnit, ok := memUnits[memReqUnitSuffix] - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidUnit, memReq.Unit, memReq.Key)) - } - - // Use getTypedValue to retrieve appropriate types - memLimitInterfaceVal, err := utils.GetTypedValue(memLimit.Key, memLimit.Value) - if err != nil { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, memLimit.Key, memLimit.Value)) - } - memLimitVal, ok := memLimitInterfaceVal.(float64) - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, memLimit.Key, memLimit.Value)) - } - - memReqInterfaceVal, err := utils.GetTypedValue(memReq.Key, memReq.Value) - if err != nil { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, memReq.Key, memReq.Value)) - } - - memReqVal, ok := memReqInterfaceVal.(float64) - if !ok { - return errors.New(fmt.Sprintf(bean.InvalidTypeValue, memReq.Key, memReq.Value)) - } - - if !validLimReq(memLimitVal, memLimitUnit.ConversionFactor, memReqVal, memReqUnit.ConversionFactor) { - return errors.New(bean.MEMLimReqErrorCompErr) - } - return nil -} -func validLimReq(lim, limFactor, req, reqFactor float64) bool { - // this condition should be true for valid case => (lim/req)*(lf/rf) >= 1 - limitToReqRatio := lim / req - convFactor := limFactor / reqFactor - return limitToReqRatio*convFactor >= 1 -} diff --git a/pkg/infraConfig/service/helper.go b/pkg/infraConfig/service/helper.go new file mode 100644 index 0000000000..571d570499 --- /dev/null +++ b/pkg/infraConfig/service/helper.go @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package service + +import ( + "github.com/caarlos0/env" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/devtron-labs/devtron/pkg/infraConfig/util" + "github.com/devtron-labs/devtron/pkg/pipeline/types" + "github.com/devtron-labs/devtron/pkg/sql" + "github.com/devtron-labs/devtron/util/sliceUtil" + "slices" +) + +func prepareConfigurationsAndMappings(creatableConfigs []*repository.InfraProfileConfigurationEntity, dbConfigs []*repository.InfraProfileConfigurationEntity, + existingPlatforms []string, profileId int, migrationRequired bool) ([]*repository.InfraProfileConfigurationEntity, []*repository.ProfilePlatformMapping) { + defaultDbConfigMap := util.CreateConfigKeyPlatformMap(dbConfigs) + existingPlatformMap := sliceUtil.GetMapOf(existingPlatforms, true) + var creatableConfigurations []*repository.InfraProfileConfigurationEntity + var platformMappings []*repository.ProfilePlatformMapping + platformsAdded := make(map[string]bool) + + for _, config := range creatableConfigs { + platform := config.ProfilePlatformMapping.Platform + if platform == "" { + platform = v1.RUNNER_PLATFORM + } + keyPlatform := v1.ConfigKeyPlatformKey{Key: config.Key, Platform: platform} + + if !defaultDbConfigMap[keyPlatform] { + config.Active = true + config.UniqueId = repository.GetUniqueId(profileId, platform) + config.ProfileId = profileId // maintained for backward compatibility + config.ProfilePlatformMapping = &repository.ProfilePlatformMapping{ + ProfileId: profileId, + Platform: platform, + } + config.AuditLog = sql.NewDefaultAuditLog(1) + creatableConfigurations = append(creatableConfigurations, config) + } + + if migrationRequired && !existingPlatformMap[platform] && !platformsAdded[platform] { + platformsAdded[platform] = true + platformMappings = append(platformMappings, &repository.ProfilePlatformMapping{ + ProfileId: profileId, + Platform: platform, + Active: true, + AuditLog: sql.NewDefaultAuditLog(1), + UniqueId: repository.GetUniqueId(profileId, platform), + }) + } + } + return creatableConfigurations, platformMappings +} + +func getAppliedConfigForProfileV0(profile *v1.ProfileBeanDto, defaultConfigurationsMap map[string][]*v1.ConfigurationBean) *v1.ProfileBeanDto { + if len(profile.GetConfigurations()) == 0 { + profile.Configurations = defaultConfigurationsMap + return profile + } + for platform, defaultConfigurations := range defaultConfigurationsMap { + extraConfigurations := make([]*v1.ConfigurationBean, 0) + for _, defaultConfiguration := range defaultConfigurations { + if !slices.ContainsFunc(profile.GetConfigurations()[platform], func(config *v1.ConfigurationBean) bool { + return config.Key == defaultConfiguration.Key + }) { + extraConfigurations = append(extraConfigurations, defaultConfiguration) + } + } + // if the profile doesn't have the default configuration, add it to the profile + profile.GetConfigurations()[platform] = append(profile.GetConfigurations()[platform], extraConfigurations...) + } + return profile +} + +func filterCreatableConfigForDefaultAndOverrideEnvConfigs(envConfigs, dbConfigs []*repository.InfraProfileConfigurationEntity) ([]*repository.InfraProfileConfigurationEntity, []*repository.InfraProfileConfigurationEntity) { + creatableConfigs := make([]*repository.InfraProfileConfigurationEntity, 0) + // Create a map for faster lookups of DB configurations by key + dbConfigMap := make(map[v1.ConfigKeyStr]*repository.InfraProfileConfigurationEntity) + for _, dbConfig := range dbConfigs { + if dbConfig.ProfilePlatformMapping.Platform == v1.RUNNER_PLATFORM { + dbConfigMap[util.GetConfigKeyStr(dbConfig.Key)] = dbConfig + } + } + // Override environment configurations with database configurations + for i, envConfig := range envConfigs { + if dbConfig, exists := dbConfigMap[util.GetConfigKeyStr(envConfig.Key)]; exists { + // Create a copy of dbConfig to avoid mutating the original + copiedConfig := *dbConfig + envConfigs[i] = &copiedConfig + } else { + creatableConfigs = append(creatableConfigs, envConfigs[i]) + } + } + return creatableConfigs, envConfigs +} + +func getConfiguredInfraConfigKeys(platform string, configurations []*v1.ConfigurationBean) v1.InfraConfigKeys { + // Get the supported keys for the platform, + // and mark the ones that are present + supportedConfigKeys := util.GetConfigKeysMapForPlatform(platform) + // Mark the keys that are present + for _, config := range configurations { + if supportedConfigKeys.IsSupported(config.Key) && config.Active { + supportedConfigKeys = supportedConfigKeys.MarkConfigured(config.Key) + } + } + return supportedConfigKeys +} + +func getDefaultInfraConfigFromEnv(envConfig *types.CiConfig) (*v1.InfraConfig, error) { + infraConfiguration := &v1.InfraConfig{} + err := env.Parse(infraConfiguration) + if err != nil { + return infraConfiguration, err + } + infraConfiguration, err = updateEntInfraConfigFromEnv(infraConfiguration, envConfig) + if err != nil { + return infraConfiguration, err + } + return infraConfiguration, nil +} diff --git a/pkg/infraConfig/service/helper_ent.go b/pkg/infraConfig/service/helper_ent.go new file mode 100644 index 0000000000..fd63dff5f7 --- /dev/null +++ b/pkg/infraConfig/service/helper_ent.go @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package service + +import ( + v1 "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/pipeline/types" +) + +func updateEntInfraConfigFromEnv(infraConfiguration *v1.InfraConfig, envConfig *types.CiConfig) (*v1.InfraConfig, error) { + return infraConfiguration, nil +} diff --git a/pkg/infraConfig/service/infraConfigService.go b/pkg/infraConfig/service/infraConfigService.go index 3ce37f7179..4b2e1e5e88 100644 --- a/pkg/infraConfig/service/infraConfigService.go +++ b/pkg/infraConfig/service/infraConfigService.go @@ -18,363 +18,958 @@ package service import ( "fmt" - "github.com/caarlos0/env" + globalUtil "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/app" + "github.com/devtron-labs/devtron/pkg/attributes" + "github.com/devtron-labs/devtron/pkg/devtronResource/read" "github.com/devtron-labs/devtron/pkg/infraConfig/adapter" - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/config" + infraErrors "github.com/devtron-labs/devtron/pkg/infraConfig/errors" "github.com/devtron-labs/devtron/pkg/infraConfig/repository" - "github.com/devtron-labs/devtron/pkg/infraConfig/units" - util2 "github.com/devtron-labs/devtron/pkg/infraConfig/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/util" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters" + "github.com/devtron-labs/devtron/pkg/pipeline/types" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" "github.com/devtron-labs/devtron/pkg/sql" + util2 "github.com/devtron-labs/devtron/util" + "github.com/devtron-labs/devtron/util/sliceUtil" "github.com/go-pg/pg" "github.com/pkg/errors" "go.uber.org/zap" + "net/http" "time" ) type InfraConfigService interface { - - // GetConfigurationUnits fetches all the units for the configurations. - GetConfigurationUnits() map[bean.ConfigKeyStr]map[string]units.Unit // GetProfileByName fetches the profile and its configurations matching the given profileName. - GetProfileByName(name string) (*bean.ProfileBeanDto, error) + GetProfileByName(name string) (*v1.ProfileBeanDto, error) // UpdateProfile updates the profile and its configurations matching the given profileName. // If profileName is empty, it will return an error. - UpdateProfile(userId int32, profileName string, profileBean *bean.ProfileBeanDto) error - - GetInfraConfigurationsByScopeAndPlatform(scope *bean.Scope, platform string) (*bean.InfraConfig, error) + // This also takes care of the platform update and delete, the default platform cannot be deleted. + UpdateProfile(userId int32, profileName string, profileBean *v1.ProfileBeanDto) error + // Deprecated: UpdateProfileV0 is deprecated in favor of UpdateProfile + UpdateProfileV0(userId int32, profileName string, profileToUpdate *v1.ProfileBeanDto) error + // GetConfigurationUnits fetches all the units for the configurations. + GetConfigurationUnits() (map[v1.ConfigKeyStr]map[string]v1.Unit, error) + // GetConfigurationsByScopeAndTargetPlatforms fetches the infra configurations for the given scope and targetPlatforms. + GetConfigurationsByScopeAndTargetPlatforms(scope resourceQualifiers.Scope, targetPlatformsList []string) (map[string]*v1.InfraConfig, error) + HandleInfraConfigTriggerAudit(workflowId int, triggeredBy int32, infraConfigs map[string]*v1.InfraConfig) error + InfraConfigServiceEnt } type InfraConfigServiceImpl struct { - logger *zap.SugaredLogger - infraProfileRepo repository.InfraConfigRepository - appService app.AppService - units *units.Units - infraConfig *bean.InfraConfig + logger *zap.SugaredLogger + infraProfileRepo repository.InfraConfigRepository + infraConfig *v1.InfraConfig + infraConfigClient config.InfraConfigClient + + appService app.AppService + dtResourceSearchableKeyService read.DevtronResourceSearchableKeyService + qualifierMappingService resourceQualifiers.QualifierMappingService + ciConfig *types.CiConfig + attributesService attributes.AttributesService } func NewInfraConfigServiceImpl(logger *zap.SugaredLogger, infraProfileRepo repository.InfraConfigRepository, appService app.AppService, - units *units.Units) (*InfraConfigServiceImpl, error) { - infraConfiguration := &bean.InfraConfig{} - err := env.Parse(infraConfiguration) + dtResourceSearchableKeyService read.DevtronResourceSearchableKeyService, + qualifierMappingService resourceQualifiers.QualifierMappingService, + attributesService attributes.AttributesService, + infraConfigClient config.InfraConfigClient, + variables *util2.EnvironmentVariables) (*InfraConfigServiceImpl, error) { + envConfig, err := types.GetCiConfig() if err != nil { - return nil, err + return nil, fmt.Errorf("error retrieving CiConfig: %v", err) + } + infraConfiguration, err := getDefaultInfraConfigFromEnv(envConfig) + if err != nil { + return nil, fmt.Errorf("error retrieving default infra config: %v", err) } infraProfileService := &InfraConfigServiceImpl{ - logger: logger, - infraProfileRepo: infraProfileRepo, - appService: appService, - units: units, - infraConfig: infraConfiguration, + logger: logger, + infraProfileRepo: infraProfileRepo, + infraConfig: infraConfiguration, + appService: appService, + dtResourceSearchableKeyService: dtResourceSearchableKeyService, + qualifierMappingService: qualifierMappingService, + attributesService: attributesService, + infraConfigClient: infraConfigClient, + ciConfig: envConfig, + } + if !variables.InternalEnvVariables.IsDevelopmentEnv() { + err = infraProfileService.loadDefaultProfile() + if err != nil { + return nil, fmt.Errorf("error loading default profile: %v", err) + } } - err = infraProfileService.loadDefaultProfile() return infraProfileService, err } -func (impl *InfraConfigServiceImpl) GetProfileByName(name string) (*bean.ProfileBeanDto, error) { +func (impl *InfraConfigServiceImpl) GetProfileByName(name string) (*v1.ProfileBeanDto, error) { infraProfile, err := impl.infraProfileRepo.GetProfileByName(name) - if err != nil { - impl.logger.Errorw("error in fetching default profile", "error", err) + if err != nil && !globalUtil.IsErrNoRows(err) { + impl.logger.Errorw("error in fetching profile", "profileName", name, "error", err) return nil, err + } else if globalUtil.IsErrNoRows(err) { + impl.logger.Errorw("profile does not exist", "profileName", name, "error", err) + return nil, globalUtil.NewApiError(http.StatusNotFound, infraErrors.ProfileDoNotExists, infraErrors.ProfileDoNotExists) } - profileBean := adapter.ConvertToProfileBean(infraProfile) - infraConfigurations, err := impl.infraProfileRepo.GetConfigurationsByProfileIds([]int{infraProfile.Id}) + infraConfigurations, err := impl.infraProfileRepo.GetConfigurationsByProfileIds(sliceUtil.GetSliceOf(infraProfile.Id)) if err != nil { - impl.logger.Errorw("error in fetching default configurations", "error", err) + impl.logger.Errorw("error in fetching configurations using profileId", "profileId", infraProfile.Id, "error", err) return nil, err } - - configurationBeans, err := adapter.ConvertToPlatformMap(infraConfigurations, profileBean.Name) + platformsList, err := impl.infraProfileRepo.GetPlatformListByProfileId(infraProfile.Id) if err != nil { - impl.logger.Errorw("error in fetching default configurations", "error", err) + impl.logger.Errorw("error in fetching platforms using profileId", "profileId", infraProfile.Id) return nil, err } + configurationBeans := make(map[string][]*v1.ConfigurationBean) + if infraConfigurations != nil { + configurationBeans, err = impl.infraConfigClient.GetConfigurationBeansForProfile(infraConfigurations, profileBean.GetName()) + if err != nil { + impl.logger.Errorw("error in converting infraConfigurations into platformMap", "profileName", profileBean.GetName(), "error", err) + return nil, err + } + } - profileBean.Configurations = configurationBeans - appCount, err := impl.appService.GetActiveCiCdAppsCount() - if err != nil { - impl.logger.Errorw("error in fetching app count for default profile", "error", err) - return nil, err + for _, platform := range platformsList { + if _, exists := configurationBeans[platform]; !exists { + configurationBeans[platform] = []*v1.ConfigurationBean{} + } } - profileBean.AppCount = appCount - return &profileBean, nil -} -func (impl *InfraConfigServiceImpl) UpdateProfile(userId int32, profileName string, profileToUpdate *bean.ProfileBeanDto) error { - // validation + profileBean.Configurations = configurationBeans + return profileBean, nil +} - //here we are setting as it will get validate later.. //for maintaining the backward compatibility - if !profileToUpdate.BuildxDriverType.IsValid() && profileToUpdate.BuildxDriverType == "" { - profileToUpdate.BuildxDriverType = bean.BuildxK8sDriver +func (impl *InfraConfigServiceImpl) UpdateProfile(userId int32, profileName string, profileToUpdate *v1.ProfileBeanDto) error { + if !util.IsValidProfileNameRequested(profileName, profileToUpdate.GetName()) { + impl.logger.Errorw("error in validating profile name change", "profileName", profileName, "profileToUpdate", profileToUpdate) + return globalUtil.NewApiError(http.StatusBadRequest, infraErrors.InvalidProfileNameChangeRequested, infraErrors.InvalidProfileNameChangeRequested) } - - defaultProfile, err := impl.GetProfileByName(profileName) + err := impl.validateUpdateRequest(profileToUpdate, profileName) + if err != nil { + impl.logger.Errorw("error in validating payload", "profileName", profileName, "error", err) + return globalUtil.NewApiError(http.StatusBadRequest, err.Error(), err.Error()) + } + existingPlatforms, err := impl.infraProfileRepo.GetPlatformsByProfileName(profileName) if err != nil { - impl.logger.Errorw("error in fetching default profile", "profileName", profileName, "profileCreateRequest", profileToUpdate, "error", err) + impl.logger.Errorw("error in fetching list of the platforms for the profile", "profileName", profileName, "error", err) return err } - if err = impl.validate(profileToUpdate, defaultProfile); err != nil { - impl.logger.Errorw("error occurred in validation the profile create request", "profileName", profileName, "profileCreateRequest", profileToUpdate, "error", err) + updatableProfilePlatforms, creatableProfilePlatforms, err := impl.getCreatableAndUpdatableProfilePlatforms(userId, profileToUpdate, profileName, existingPlatforms) + if err != nil { + impl.logger.Errorw("Error in getCreatableAndUpdatableProfilePlatforms", "profile", profileToUpdate, "err", err) return err } - // validations end - - profileToUpdate.Id = defaultProfile.Id + profileFromDb, err := impl.infraProfileRepo.GetProfileByName(profileName) + if err != nil { + impl.logger.Errorw("error in fetching profile", "profileName", profileName, "error", err) + return err + } + profileToUpdate.Id = profileFromDb.Id infraProfileEntity := adapter.ConvertToInfraProfileEntity(profileToUpdate) // user couldn't delete the profile, always set this to active infraProfileEntity.Active = true - //todo make it compatible with ent - - infraConfigurations := adapter.ConvertFromPlatformMap(profileToUpdate.Configurations, defaultProfile, userId) - + sanitizedUpdatableInfraConfigurations, sanitizedCreatableInfraConfigurations, err := impl.sanitizeAndGetUpdatableAndCreatableConfigurationEntities(userId, profileName, profileToUpdate, existingPlatforms) + if err != nil { + // if sanity failed throw the error + impl.logger.Errorw("Error in sanitizeAndGetUpdatableAndCreatableConfigurationEntities", "profile", profileToUpdate, "err", err) + return err + } tx, err := impl.infraProfileRepo.StartTx() if err != nil { impl.logger.Errorw("error in starting transaction to update profile", "profileBean", profileToUpdate, "error", err) return err } - defer func(infraProfileRepo repository.InfraConfigRepository, tx *pg.Tx) { - err := infraProfileRepo.RollbackTx(tx) + defer impl.infraProfileRepo.RollbackTx(tx) + infraProfileEntity.UpdateAuditLog(userId) + err = impl.infraProfileRepo.UpdateProfile(tx, profileName, infraProfileEntity) + if err != nil { + impl.logger.Errorw("error in updating profile", "infraProfile", infraProfileEntity, "error", err) + return err + } + // Update existing platform mappings in the database + if len(updatableProfilePlatforms) > 0 { + err = impl.infraProfileRepo.UpdatePlatformProfileMapping(tx, updatableProfilePlatforms) if err != nil { - impl.logger.Errorw("error in rolling back transaction to update profile", "error", err) + impl.logger.Errorw("Error updating profile platform mappings", "profile", profileToUpdate, "err", err) + return err } - }(impl.infraProfileRepo, tx) + } + // Create new platform mappings in the database + if len(creatableProfilePlatforms) > 0 { + err = impl.infraProfileRepo.CreatePlatformProfileMapping(tx, creatableProfilePlatforms) + if err != nil { + impl.logger.Errorw("Error creating profile platform mappings", "profile", profileToUpdate, "err", err) + return err + } + } - infraProfileEntity.UpdatedOn = time.Now() - infraProfileEntity.UpdatedBy = userId - err = impl.infraProfileRepo.UpdateProfile(tx, profileName, infraProfileEntity) + sanitizedUpdatableInfraConfigurations = adapter.UpdatePlatformMappingInConfigEntities(sanitizedUpdatableInfraConfigurations, updatableProfilePlatforms) + if len(sanitizedUpdatableInfraConfigurations) > 0 { + err = impl.infraProfileRepo.UpdateConfigurations(tx, sanitizedUpdatableInfraConfigurations) + if err != nil { + impl.logger.Errorw("error in creating configurations", "updatableInfraConfigurations", sanitizedUpdatableInfraConfigurations, "error", err) + return err + } + err = impl.infraConfigClient.HandlePostUpdateOperations(tx, sanitizedUpdatableInfraConfigurations) + if err != nil { + impl.logger.Errorw("error in handling post update operations", "updatableInfraConfigurations", sanitizedUpdatableInfraConfigurations, "error", err) + return err + } + } + + sanitizedCreatableInfraConfigurations = adapter.UpdatePlatformMappingInConfigEntities(sanitizedCreatableInfraConfigurations, creatableProfilePlatforms) + if len(sanitizedCreatableInfraConfigurations) > 0 { + err = impl.infraProfileRepo.CreateConfigurations(tx, sanitizedCreatableInfraConfigurations) + if err != nil { + impl.logger.Errorw("error in creating configurations", "creatableInfraConfigurations", sanitizedCreatableInfraConfigurations, "error", err) + return err + } + err = impl.infraConfigClient.HandlePostCreateOperations(tx, sanitizedCreatableInfraConfigurations) + if err != nil { + impl.logger.Errorw("error in handling post create operations", "creatableInfraConfigurations", sanitizedCreatableInfraConfigurations, "error", err) + return err + } + } + err = impl.infraProfileRepo.CommitTx(tx) if err != nil { - impl.logger.Errorw("error in updating profile", "error", "profileName", profileName, "profileCreateRequest", profileToUpdate, err) + impl.logger.Errorw("error in committing transaction to update profile", "profileCreateRequest", profileToUpdate, "error", err) return err } - err = impl.infraProfileRepo.UpdateConfigurations(tx, infraConfigurations) + return nil +} + +func (impl *InfraConfigServiceImpl) UpdateProfileV0(userId int32, profileName string, profileToUpdate *v1.ProfileBeanDto) error { + if profileName == v1.DEFAULT_PROFILE_NAME { + profileName = v1.GLOBAL_PROFILE_NAME + } + configurationEntities, err := impl.infraProfileRepo.GetConfigurationsByProfileName(profileName) if err != nil { - impl.logger.Errorw("error in creating configurations", "error", "profileName", profileName, "profileCreateRequest", profileToUpdate, err) + impl.logger.Errorw("Error in GetConfigurationsByProfileName", "profileName", profileName, "error", err) return err } - err = impl.infraProfileRepo.CommitTx(tx) + platformMapConfigs, err := impl.infraConfigClient.GetConfigurationBeansForProfile(configurationEntities, profileName) if err != nil { - impl.logger.Errorw("error in committing transaction to update profile", "profileCreateRequest", profileToUpdate, "error", err) + impl.logger.Errorw("error in converting configurations into platformMap", "profileName", profileName, "error", err) + return err + } + adapter.FillMissingConfigurationsForThePayloadV0(profileToUpdate, platformMapConfigs) + err = impl.UpdateProfile(userId, profileName, profileToUpdate) + if err != nil { + impl.logger.Errorw("error in performing Update ", "profileCreateRequest", profileToUpdate, "error", err) return err } return nil } -// loadDefaultProfile loads default configurations from environment and save them in db. -// this will only create the default profile only once if not exists in db.(container restarts won't create new default profile everytime) -// this will load the default configurations provided in InfraConfig. if db is in out of sync with InfraConfig then it will create new entries for those missing configurations in db. -func (impl *InfraConfigServiceImpl) loadDefaultProfile() error { +func (impl *InfraConfigServiceImpl) GetConfigurationUnits() (map[v1.ConfigKeyStr]map[string]v1.Unit, error) { + return impl.infraConfigClient.GetConfigurationUnits() +} - profile, err := impl.infraProfileRepo.GetProfileByName(bean.GLOBAL_PROFILE_NAME) +func (impl *InfraConfigServiceImpl) GetConfigurationsByScopeAndTargetPlatforms(scope resourceQualifiers.Scope, targetPlatformsList []string) (map[string]*v1.InfraConfig, error) { + resp := make(map[string]*v1.InfraConfig) + // Get the configuration from scope then, + // Parse all target Platforms and if the configuration[targetPlatform] found => set the in the res[targetPlatform] + // If not found or exist, then set res[targetPlatform]= configuration[default] + appliedProfileConfig, defaultProfileConfig, err := impl.getAppliedProfileForTriggerScope(infraGetters.GetInfraConfigScope(scope)) + if err != nil { + impl.logger.Errorw("error in fetching configurations", "scope", scope, "error", err) + return resp, err + } + resolvedAppliedConfig, variableSnapshot, err := impl.resolveScopeVariablesForAppliedProfile(scope, appliedProfileConfig) + if err != nil { + impl.logger.Errorw("error in resolving scope variables", "appliedProfileConfig", appliedProfileConfig, "error", err) + return resp, err + } + appliedProfileConfig = resolvedAppliedConfig + platformToInfraConfigMap, err := impl.getAppliedInfraConfigForProfile(appliedProfileConfig, defaultProfileConfig, variableSnapshot, targetPlatformsList) + if err != nil { + impl.logger.Errorw("error in fetching infra configurations", "appliedProfileConfig", appliedProfileConfig, "error", err) + return resp, err + } + return platformToInfraConfigMap, err +} + +func (impl *InfraConfigServiceImpl) HandleInfraConfigTriggerAudit(workflowId int, triggeredBy int32, infraConfigs map[string]*v1.InfraConfig) error { + return impl.infraConfigClient.HandleInfraConfigTriggerAudit(workflowId, triggeredBy, infraConfigs) +} + +// loadDefaultProfile: loads default configurations from environment and save them in the DB. +// - create the default profile only once if not exists in db already. +// (container restarts won't create a new default profile everytime) +// - load the default configurations provided in bean.InfraConfig. +// - if DB is out of sync with bean.InfraConfig, +// then it will create the new entries in DB, only for the missing configurations. +// - also handles the one-time migration for buildx K8sDriverOpts from environment, +// then update the marker in attribute table as true (i.e. migrated). +func (impl *InfraConfigServiceImpl) loadDefaultProfile() error { + profile, err := impl.infraProfileRepo.GetProfileByName(v1.GLOBAL_PROFILE_NAME) // make sure about no rows error if err != nil && !errors.Is(err, pg.ErrNoRows) { - impl.logger.Errorw("error in fetching default profile", "error", err) + impl.logger.Errorw("error in getting profile GetProfileByName", "err", err) return err } profileCreationRequired := errors.Is(err, pg.ErrNoRows) + migrationRequired, err := impl.isMigrationRequired() + if err != nil { + impl.logger.Errorw("error in checking if migration is required", "error", err) + return err + } + + // step 1: initiate Transaction tx, err := impl.infraProfileRepo.StartTx() if err != nil { - impl.logger.Errorw("error in starting transaction to save default configurations", "error", err) + impl.logger.Errorw("error starting transaction at loadDefaultProfile", "error", err) return err } - defer func(infraProfileRepo repository.InfraConfigRepository, tx *pg.Tx) { - err := infraProfileRepo.RollbackTx(tx) - if err != nil { - impl.logger.Errorw("error in rolling back transaction to save default configurations", "error", err) - } - }(impl.infraProfileRepo, tx) + defer impl.infraProfileRepo.RollbackTx(tx) + + // step 2: creating Global Profile in case when required if profileCreationRequired { - // if default profiles not found then create default profile - defaultProfile := &repository.InfraProfileEntity{ - Name: bean.GLOBAL_PROFILE_NAME, - Description: "", - Active: true, - AuditLog: sql.NewDefaultAuditLog(1), + profile, err = impl.createGlobalProfile(tx) + if err != nil { + impl.logger.Errorw("error in creating global profile", "error", err) + return err } + } + + // step 3: get creatableConfigurations and creatablePlatformMappings + creatableConfigurations, creatablePlatformMappings, err := impl.getCreatableConfigurationsAndPlatformMappings(migrationRequired, profile.Id) + if err != nil { + impl.logger.Errorw("error in loading configuration at loadConfiguration", "err", err) + return err + } - err = impl.infraProfileRepo.CreateProfile(tx, defaultProfile) + //step 4: create configurations and platform + err = impl.createConfigurationsAndPlatforms(creatableConfigurations, creatablePlatformMappings, migrationRequired, tx) + if err != nil { + impl.logger.Errorw("error creating configurations and platforms", "error", err) + return err + } + + // step 5: mark the key if the migration was required + if migrationRequired { + err = impl.updateBuildxDriverTypeInExistingProfiles(tx) if err != nil { - impl.logger.Errorw("error in saving default profile", "error", err) + impl.logger.Errorw("error in updating buildx driver type in existing profiles", "error", err) + return err + } + err = impl.markMigrationComplete(tx) + if err != nil { + impl.logger.Errorw("error in marking migration complete markMigrationComplete", "err", err) return err } - profile = defaultProfile } - var nodeselector []string - defaultConfigurationsFromEnv, err := adapter.LoadInfraConfigInEntities(impl.infraConfig, nodeselector, "", "") + + err = impl.infraProfileRepo.CommitTx(tx) if err != nil { - impl.logger.Errorw("error in loading default configurations from environment", "error", err) + impl.logger.Errorw("error in committing transaction to save default configurations", "error", err) return err } + return nil +} + +func (impl *InfraConfigServiceImpl) createConfigurationsAndPlatforms(creatableConfigurations []*repository.InfraProfileConfigurationEntity, + platformMappings []*repository.ProfilePlatformMapping, migrationRequired bool, tx *pg.Tx) error { + if migrationRequired && len(platformMappings) > 0 { + err := impl.infraProfileRepo.CreatePlatformProfileMapping(tx, platformMappings) + if err != nil { + impl.logger.Errorw("error saving platform mappings", "error", err) + return err + } + } + creatableConfigurations = adapter.UpdatePlatformMappingInConfigEntities(creatableConfigurations, platformMappings) + if len(creatableConfigurations) > 0 { + err := impl.infraProfileRepo.CreateConfigurations(tx, creatableConfigurations) + if err != nil { + impl.logger.Errorw("error saving configurations", "error", err) + return err + } + } + return nil +} + +func (impl *InfraConfigServiceImpl) getCreatableConfigurationsAndPlatformMappings(migrationRequired bool, profileId int) ([]*repository.InfraProfileConfigurationEntity, []*repository.ProfilePlatformMapping, error) { + envConfigs, err := impl.loadConfiguration(profileId) + if err != nil { + impl.logger.Errorw("error in loading configuration at loadConfiguration", "err", err) + return nil, nil, err + } + + existingPlatformMappings, err := impl.infraProfileRepo.GetPlatformsByProfileById(profileId) + if err != nil { + impl.logger.Errorw("error in fetching ciRunnerProfilePlatform", "error", err) + return nil, nil, err + } - // get db configurations and create new entries if db is out of sync - defaultConfigurationsFromDB, err := impl.infraProfileRepo.GetConfigurationsByProfileName(bean.GLOBAL_PROFILE_NAME) + creatableConfigs := make([]*repository.InfraProfileConfigurationEntity, 0) + + dbConfigs, err := impl.infraProfileRepo.GetConfigurationsByProfileId(profileId) if err != nil && !errors.Is(err, pg.ErrNoRows) { - impl.logger.Errorw("error in fetching default configurations", "error", err) - return err + impl.logger.Errorw("error fetching default configurations from database", "error", err) + return nil, nil, err } - defaultConfigurationsFromDBMap := make(map[bean.ConfigKey]bool) - for _, defaultConfigurationFromDB := range defaultConfigurationsFromDB { - defaultConfigurationsFromDBMap[defaultConfigurationFromDB.Key] = true + + // filterOut the creatable Configs found in the db + creatableConfigsForDefault, envConfigs := filterCreatableConfigForDefaultAndOverrideEnvConfigs(envConfigs, dbConfigs) + + if len(creatableConfigsForDefault) > 0 { + creatableConfigs = append(creatableConfigs, creatableConfigsForDefault...) } - creatableConfigurations := make([]*repository.InfraProfileConfigurationEntity, 0, len(defaultConfigurationsFromEnv)) - creatableProfilePlatformMapping := make([]*repository.ProfilePlatformMapping, 0) + // check for the migration required and BuildxK8sDriverOptions present to append in the creatableConfigs + if migrationRequired && impl.ciConfig != nil && impl.ciConfig.BuildxK8sDriverOptions != "" { + cmCreatableConfigs, err := impl.getCreatableK8sDriverConfigs(profileId, envConfigs) + if err != nil { + impl.logger.Errorw("error in getting creatable k8s driver configs", "error", err, "profileId", profileId) + return nil, nil, err + } + if len(cmCreatableConfigs) > 0 { + creatableConfigs = append(creatableConfigs, cmCreatableConfigs...) + } + } + + existingPlatforms := sliceUtil.NewSliceFromFuncExec(existingPlatformMappings, + func(existingPlatformMapping *repository.ProfilePlatformMapping) string { + return existingPlatformMapping.Platform + }) + + creatableConfigs, creatableProfilePlatformMappings := prepareConfigurationsAndMappings(creatableConfigs, dbConfigs, existingPlatforms, profileId, migrationRequired) + + creatableConfigs = adapter.UpdatePlatformMappingInConfigEntities(creatableConfigs, existingPlatformMappings) - platformsFromDb, err := impl.infraProfileRepo.GetPlatformsByProfileName(bean.GLOBAL_PROFILE_NAME) + return creatableConfigs, creatableProfilePlatformMappings, nil +} + +func (impl *InfraConfigServiceImpl) loadConfiguration(profileId int) ([]*repository.InfraProfileConfigurationEntity, error) { + envConfigs, err := impl.infraConfigClient.GetInfraConfigEntities(profileId, impl.infraConfig) + if err != nil { + impl.logger.Errorw("error loading default configurations from environment", "error", err) + return nil, err + } + return envConfigs, nil +} + +func (impl *InfraConfigServiceImpl) validateUpdateRequest(profileToUpdate *v1.ProfileBeanDto, profileName string) error { + globalProfile, err := impl.GetProfileByName(v1.GLOBAL_PROFILE_NAME) + if err != nil { + impl.logger.Errorw("error in fetching default profile", "profileName", v1.GLOBAL_PROFILE_NAME, "profileToUpdate", profileToUpdate, "error", err) + return err + } + exist, err := impl.infraProfileRepo.CheckIfProfileExistsByName(profileName) + if err != nil { + impl.logger.Errorw("error in fetching profile by name", "profileName", profileName, "error", err) + return err + } + if !exist { + impl.logger.Errorw("profile does not exist", "profileName", profileName, "error", infraErrors.ProfileDoNotExists) + return globalUtil.NewApiError(http.StatusBadRequest, infraErrors.ProfileDoNotExists, infraErrors.ProfileDoNotExists) + } + exist, err = impl.infraProfileRepo.CheckIfProfileExistsByName(profileToUpdate.GetName()) if err != nil && !errors.Is(err, pg.ErrNoRows) { - impl.logger.Errorw("error in fetching platforms from db", "error", err) + impl.logger.Errorw("error in fetching profile by name", "profileName", profileName, "error", err) return err } + if exist && profileName != profileToUpdate.GetName() { + impl.logger.Errorw("profile already exist", "profileNameRequested", profileToUpdate.GetName(), "err", infraErrors.ProfileAlreadyExistsErr) + return globalUtil.NewApiError(http.StatusBadRequest, infraErrors.ProfileAlreadyExistsErr, infraErrors.ProfileAlreadyExistsErr) + } - runnerPlatFormMapping := &repository.ProfilePlatformMapping{} - //one platform is expected - if len(platformsFromDb) > 0 { - for _, platform := range platformsFromDb { - if platform.Platform == bean.RUNNER_PLATFORM { - runnerPlatFormMapping = platform - break - } + err = impl.validate(profileToUpdate, globalProfile) + if err != nil { + impl.logger.Errorw("error in validating payload", "profileName", profileName, "error", err) + return globalUtil.NewApiError(http.StatusBadRequest, err.Error(), err.Error()) + } + return nil +} + +func (impl *InfraConfigServiceImpl) validate(profileToUpdate, defaultProfile *v1.ProfileBeanDto) error { + err := util.ValidatePayloadConfig(profileToUpdate) + if err != nil { + return err + } + + _, err = impl.infraConfigClient.Validate(profileToUpdate, defaultProfile) + if err != nil { + err = errors.Wrap(err, infraErrors.PayloadValidationError) + return err + } + return nil +} + +func (impl *InfraConfigServiceImpl) getCreatableAndUpdatableProfilePlatforms(userId int32, profileToUpdate *v1.ProfileBeanDto, + profileName string, existingPlatforms []*repository.ProfilePlatformMapping) ([]*repository.ProfilePlatformMapping, []*repository.ProfilePlatformMapping, error) { + var err error + // Create a map for updated platforms + updatedMap := make(map[string]bool) + updatedMap[v1.RUNNER_PLATFORM] = false + for platform := range profileToUpdate.GetConfigurations() { + updatedMap[platform] = true + } + if !updatedMap[v1.RUNNER_PLATFORM] { + return nil, nil, + globalUtil.NewApiError(http.StatusBadRequest, infraErrors.DeletionBlockedForDefaultPlatform, infraErrors.DeletionBlockedForDefaultPlatform) + } + + infraProfileEntity, err := impl.infraProfileRepo.GetProfileByName(profileName) + if err != nil { + impl.logger.Errorw("error in fetching list of the platforms for the profile,") + return nil, nil, err + } + + // Create a map for existing platforms + existingPlatformListMap := make(map[string]*repository.ProfilePlatformMapping, len(existingPlatforms)) + for _, platform := range existingPlatforms { + existingPlatformListMap[platform.Platform] = platform + } + + // Prepare platform mappings for update and creation + updatableProfilePlatformMap := make([]*repository.ProfilePlatformMapping, 0) + creatableProfilePlatformMap := make([]*repository.ProfilePlatformMapping, 0) + // Handle platforms that are in existingPlatformListMap + for platformName, platform := range existingPlatformListMap { + if !updatedMap[platformName] { + platform.Active = false + platform.UpdateAuditLog(userId) + platform.UniqueId = repository.GetUniqueId(platform.Id, platformName) + // Platform exists in existing but not in updated, mark as inactive for deletion + updatableProfilePlatformMap = append(updatableProfilePlatformMap, platform) } - } else { - runnerPlatFormMapping = &repository.ProfilePlatformMapping{ - Platform: bean.RUNNER_PLATFORM, - ProfileId: profile.Id, - Active: true, - AuditLog: sql.NewDefaultAuditLog(1), + } + + // Handle platforms that are only in updatedMap + for platform := range updatedMap { + if _, exist := existingPlatformListMap[platform]; !exist { + // Platform is new, mark for creation + creatableProfilePlatformMap = append(creatableProfilePlatformMap, &repository.ProfilePlatformMapping{ + ProfileId: infraProfileEntity.Id, + Platform: platform, + Active: true, + AuditLog: sql.NewDefaultAuditLog(userId), + UniqueId: repository.GetUniqueId(infraProfileEntity.Id, platform), + }) } } + return updatableProfilePlatformMap, creatableProfilePlatformMap, nil +} - //creating default platform if not found in db - if len(platformsFromDb) == 0 { - creatableProfilePlatformMapping = append(creatableProfilePlatformMapping, runnerPlatFormMapping) +func (impl *InfraConfigServiceImpl) sanitizeAndGetUpdatableAndCreatableConfigurationEntities(userId int32, profileName string, + profileToUpdate *v1.ProfileBeanDto, existingPlatforms []*repository.ProfilePlatformMapping) (updatableInfraConfigurations []*repository.InfraProfileConfigurationEntity, creatableInfraConfigurations []*repository.InfraProfileConfigurationEntity, err error) { + // Convert profile configurations into infraConfigurationEntities + infraConfigurationEntities, err := impl.infraConfigClient.GetInfraProfileConfigurationEntities(profileToUpdate, userId) + if err != nil { + impl.logger.Errorw("error in converting profile configurations to infraConfigurationEntities", "profileToUpdate", profileToUpdate, "error", err) + return nil, nil, err + } + // Fetch existing configurations and platforms for the given profile + existingConfigurations, err := impl.infraProfileRepo.GetConfigurationsByProfileName(profileName) + if err != nil && !errors.Is(err, infraErrors.NoPropertiesFoundError) { + impl.logger.Errorw("error in fetching existing configuration ids", "profileName", profileName, "error", err) + return updatableInfraConfigurations, creatableInfraConfigurations, err + } + // mandatory config validations for profile + for platform, configurations := range profileToUpdate.GetConfigurations() { + configuredInfraConfigKeys := getConfiguredInfraConfigKeys(platform, configurations) + // Check if any default keys are still true (missing) + missingKeys := util.GetMissingRequiredConfigKeys(profileName, platform, configuredInfraConfigKeys) + for _, missingKey := range missingKeys { + index, found := sliceUtil.Find(existingConfigurations, func(entity *repository.InfraProfileConfigurationEntity) bool { + if entity == nil || entity.ProfilePlatformMapping == nil { + return false + } + return entity.Key == util.GetConfigKey(missingKey) && entity.ProfilePlatformMapping.Platform == platform + }) + if found { + infraConfigurationEntities = append(infraConfigurationEntities, existingConfigurations[index]) + } else { + impl.logger.Errorw("missing default configuration keys for platform", "platform", platform, "profileName", profileName, "missingKey", missingKey) + errMsg := infraErrors.ConfigurationMissingError(missingKey, profileName, platform) + return nil, nil, + globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + } } - if len(creatableProfilePlatformMapping) > 0 { - err = impl.infraProfileRepo.CreatePlatformProfileMapping(tx, creatableProfilePlatformMapping) - if err != nil { - impl.logger.Errorw("error in saving default configurations", "error", err) - return err + // Separate creatable and updatable configurations + creatableInfraConfigurations = make([]*repository.InfraProfileConfigurationEntity, 0, len(infraConfigurationEntities)) + updatableInfraConfigurations = make([]*repository.InfraProfileConfigurationEntity, 0) + for _, configuration := range infraConfigurationEntities { + if configuration.Id == 0 { + creatableInfraConfigurations = append(creatableInfraConfigurations, configuration) + } else { + updatableInfraConfigurations = append(updatableInfraConfigurations, configuration) } } + // case where existingConfig is not found + if existingConfigurations == nil && len(updatableInfraConfigurations) > 0 { + return nil, nil, + globalUtil.NewApiError(http.StatusBadRequest, infraErrors.UpdatableConfigurationFoundErr, infraErrors.UpdatableConfigurationFoundErr) + } - for _, configurationFromEnv := range defaultConfigurationsFromEnv { - if ok, exist := defaultConfigurationsFromDBMap[configurationFromEnv.Key]; !exist || !ok { - configurationFromEnv.ProfileId = profile.Id - configurationFromEnv.Active = true - configurationFromEnv.ProfilePlatformMappingId = runnerPlatFormMapping.Id - configurationFromEnv.ProfilePlatformMapping.Platform = bean.RUNNER_PLATFORM - configurationFromEnv.AuditLog = sql.NewDefaultAuditLog(1) - creatableConfigurations = append(creatableConfigurations, configurationFromEnv) + if len(creatableInfraConfigurations) > 0 { + creatableInfraConfigurations, err = impl.sanitizeCreatableConfigurations(userId, profileName, creatableInfraConfigurations, existingConfigurations) + if err != nil { + return updatableInfraConfigurations, nil, globalUtil.NewApiError(http.StatusBadRequest, err.Error(), err.Error()) } } - if len(creatableConfigurations) > 0 { - err = impl.infraProfileRepo.CreateConfigurations(tx, creatableConfigurations) + if len(updatableInfraConfigurations) > 0 { + updatableInfraConfigurations, err = impl.sanitizeUpdatableConfigurations(updatableInfraConfigurations, existingConfigurations, profileName) if err != nil { - impl.logger.Errorw("error in saving default configurations", "configurations", creatableConfigurations, "error", err) - return err + return updatableInfraConfigurations, nil, globalUtil.NewApiError(http.StatusBadRequest, err.Error(), err.Error()) } } + if len(existingConfigurations) > 0 { + deletableInfraConfigurations, err := impl.sanitizeDeletableConfigurations(userId, updatableInfraConfigurations, existingConfigurations) + if err != nil { + return updatableInfraConfigurations, nil, err + } + updatableInfraConfigurations = append(updatableInfraConfigurations, deletableInfraConfigurations...) + } - err = impl.infraProfileRepo.CommitTx(tx) - if err != nil { - impl.logger.Errorw("error in committing transaction to save default configurations", "error", err) + updatableInfraConfigurations = adapter.UpdatePlatformMappingInConfigEntities(updatableInfraConfigurations, existingPlatforms) + + creatableInfraConfigurations = adapter.UpdatePlatformMappingInConfigEntities(creatableInfraConfigurations, existingPlatforms) + + return updatableInfraConfigurations, creatableInfraConfigurations, nil +} + +func (impl *InfraConfigServiceImpl) sanitizeDeletableConfigurations(userId int32, updatableInfraConfigurations, existingConfigurations []*repository.InfraProfileConfigurationEntity) ([]*repository.InfraProfileConfigurationEntity, error) { + deletableInfraConfigurations := make([]*repository.InfraProfileConfigurationEntity, 0) + if len(updatableInfraConfigurations) > 0 { + // Create a map for existing configuration IDs for O(1) lookup + updatableConfigMap := make(map[int]*repository.InfraProfileConfigurationEntity, len(updatableInfraConfigurations)) + for _, updatableConfig := range updatableInfraConfigurations { + updatableConfigMap[updatableConfig.Id] = updatableConfig + } + for _, existingConfig := range existingConfigurations { + if _, exists := updatableConfigMap[existingConfig.Id]; !exists { + existingConfig.Active = false + existingConfig.AuditLog = sql.AuditLog{ + UpdatedOn: time.Now(), + UpdatedBy: userId, + } + deletableInfraConfigurations = append(deletableInfraConfigurations, existingConfig) + } + } } - return err + //when no any updatableInfraConfigurations found means we need to delete the existingConfigurations from db + if len(existingConfigurations) > 0 && len(updatableInfraConfigurations) == 0 { + for _, existingConfig := range existingConfigurations { + existingConfig.Active = false + existingConfig.AuditLog = sql.AuditLog{ + UpdatedOn: time.Now(), + UpdatedBy: userId, + } + deletableInfraConfigurations = append(deletableInfraConfigurations, existingConfig) + } + } + return deletableInfraConfigurations, nil } -func (impl *InfraConfigServiceImpl) GetInfraConfigurationsByScopeAndPlatform(scope *bean.Scope, platform string) (*bean.InfraConfig, error) { +func (impl *InfraConfigServiceImpl) sanitizeCreatableConfigurations(userId int32, profileName string, creatableInfraConfigurations []*repository.InfraProfileConfigurationEntity, + existingConfigurations []*repository.InfraProfileConfigurationEntity) ([]*repository.InfraProfileConfigurationEntity, error) { + // Create a map with composite keys (Key|Platform) for existing configurations + existingConfigMap := make(map[string]*repository.InfraProfileConfigurationEntity, len(existingConfigurations)) + for _, existingConfig := range existingConfigurations { + compositeKey := util.GetConfigCompositeKey(existingConfig) + existingConfigMap[compositeKey] = existingConfig + } + + // Collect duplicate configurations + var duplicateConfigs []string + for _, creatableConfig := range creatableInfraConfigurations { + compositeKey := util.GetConfigCompositeKey(creatableConfig) + if _, exists := existingConfigMap[compositeKey]; exists { + duplicateConfigs = append(duplicateConfigs, fmt.Sprintf("Key: %s, UniqueId: %s", util.GetConfigKeyStr(creatableConfig.Key), creatableConfig.UniqueId)) + } + } + // If duplicates are found, log and return an error + if len(duplicateConfigs) > 0 { + impl.logger.Errorw("Duplicate creatable configurations detected", "duplicateConfigs", duplicateConfigs, "profileName", profileName) + errMsg := fmt.Sprintf("cannot create configurations as the following Key and Platform combinations already exist in the %q profile: %v", profileName, duplicateConfigs) + return nil, globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } - defaultConfigurations, err := impl.infraProfileRepo.GetConfigurationsByProfileName(bean.GLOBAL_PROFILE_NAME) - if err != nil { - impl.logger.Errorw("error in fetching default configurations", "scope", scope, "error", err) - return nil, err + // Update configurations with ProfileId, Active status, and AuditLog + for _, config := range creatableInfraConfigurations { + config.Active = true + config.AuditLog = sql.NewDefaultAuditLog(userId) } + return creatableInfraConfigurations, nil +} - defaultConfigurationsMap, err := adapter.ConvertToPlatformMap(defaultConfigurations, bean.GLOBAL_PROFILE_NAME) - if err != nil { - impl.logger.Errorw("error in fetching default configurations", "scope", scope, "error", err) - return nil, err +func (impl *InfraConfigServiceImpl) sanitizeUpdatableConfigurations(updatableInfraConfigurations []*repository.InfraProfileConfigurationEntity, existingConfigurations []*repository.InfraProfileConfigurationEntity, profileName string) ([]*repository.InfraProfileConfigurationEntity, error) { + // Create a map for existing configuration IDs for O(1) lookup + existingConfigMap := make(map[int]*repository.InfraProfileConfigurationEntity, len(existingConfigurations)) + for _, existingConfig := range existingConfigurations { + existingConfigMap[existingConfig.Id] = existingConfig + } + // Collect invalid configuration IDs + var invalidConfigs []int + for _, updatableConfig := range updatableInfraConfigurations { + if _, exists := existingConfigMap[updatableConfig.Id]; !exists { + invalidConfigs = append(invalidConfigs, updatableConfig.Id) + } } - platformConfigurationBean := defaultConfigurationsMap[platform] - if platformConfigurationBean == nil { - return &bean.InfraConfig{}, nil + // If any invalid configurations found, log and return an error + if len(invalidConfigs) > 0 { + impl.logger.Errorw("Invalid updatable configurations detected", "invalidConfigIds", invalidConfigs, "profileName", profileName) + errMsg := fmt.Sprintf("cannot update configurations with ids %v as they do not belong to %q profile", invalidConfigs, profileName) + return nil, globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) } + return updatableInfraConfigurations, nil +} - return impl.getInfraConfigForConfigBean(platformConfigurationBean), nil +func (impl *InfraConfigServiceImpl) getAppliedInfraConfigForProfile(appliedProfileConfig, defaultProfileConfig *v1.ProfileBeanDto, variableSnapshots map[string]map[string]string, targetPlatformsList []string) (map[string]*v1.InfraConfig, error) { + resp := make(map[string]*v1.InfraConfig) + for _, targetPlatform := range targetPlatformsList { + appliedConfiguration := impl.getAppliedConfigurationForTargetPlatform(appliedProfileConfig, defaultProfileConfig, targetPlatform) + infraConfigForTrigger, err := impl.getInfraConfigurationForTrigger(appliedConfiguration) + if err != nil { + impl.logger.Errorw("error in updating configurations", "appliedConfiguration", appliedConfiguration, "error", err) + return resp, err + } + if variableSnapshot, ok := variableSnapshots[targetPlatform]; ok && variableSnapshot != nil { + infraConfigForTrigger = infraConfigForTrigger.SetCiVariableSnapshot(variableSnapshot) + } + resp[targetPlatform] = infraConfigForTrigger + } + return resp, nil } -func (impl *InfraConfigServiceImpl) getInfraConfigForConfigBean(platformConfigurationBean []*bean.ConfigurationBean) *bean.InfraConfig { - infraConfiguration := &bean.InfraConfig{} - overrideInfraConfigFunc := func(config bean.ConfigurationBean) { - switch config.Key { - case bean.CPU_LIMIT: - infraConfiguration.SetCiLimitCpu(impl.getResolvedValue(config).(string)) - case bean.CPU_REQUEST: - infraConfiguration.SetCiReqCpu(impl.getResolvedValue(config).(string)) - case bean.MEMORY_LIMIT: - infraConfiguration.SetCiLimitMem(impl.getResolvedValue(config).(string)) - case bean.MEMORY_REQUEST: - infraConfiguration.SetCiReqMem(impl.getResolvedValue(config).(string)) - case bean.TIME_OUT: - infraConfiguration.SetCiDefaultTimeout(impl.getResolvedValue(config).(int64)) - } - } - for _, defaultConfigurationBean := range platformConfigurationBean { - overrideInfraConfigFunc(*defaultConfigurationBean) - } - return infraConfiguration +// getAppliedProfileForTriggerScope fetches the applied configuration for the given target platform +// - CASE 1: target platform exists in the applied configuration, +// return the applied configuration for the target platform +// - CASE 2: target platform does not exist in the applied configuration, but exists in the default configuration, +// return the default configuration for the target platform +// - CASE 3: target platform does not exist in the applied configuration and default configuration, +// return the runner configuration of the default. +// --------------------------------- Flow Chart ------------------------------------ +// | Applied Config Default Config | +// | -------------------- -------------------- | +// | | linux/arm64 | | linux/arm64 | | +// | | runner | | linux/amd64 | | +// | | | | runner | | +// | -------------------- -------------------- | +// | ------------------------------------------------------------------ | +// | | Target Platform | Returns | | +// | ------------------------------------------------------------------ | +// | | linux/arm64 | Applied Config[linux/arm64] | | +// | | linux/amd64 | Default Config[linux/amd64] | | +// | | linux/arm/v7 | Default Config[runner] | | +// | ------------------------------------------------------------------ | +// --------------------------------------------------------------------------------- +func (impl *InfraConfigServiceImpl) getAppliedConfigurationForTargetPlatform(appliedProfileConfig, defaultProfileConfig *v1.ProfileBeanDto, targetPlatform string) []*v1.ConfigurationBean { + var appliedConfiguration []*v1.ConfigurationBean + if targetConfiguration, ok := appliedProfileConfig.GetConfigurations()[targetPlatform]; ok && targetConfiguration != nil { + appliedConfiguration = appliedProfileConfig.GetConfigurations()[targetPlatform] + } else { + if defaultConfiguration, ok := defaultProfileConfig.GetConfigurations()[targetPlatform]; ok && defaultConfiguration != nil { + appliedConfiguration = defaultConfiguration + } else { + appliedConfiguration = defaultProfileConfig.GetConfigurations()[v1.RUNNER_PLATFORM] + } + } + return appliedConfiguration } -func (impl *InfraConfigServiceImpl) getResolvedValue(configurationBean bean.ConfigurationBean) interface{} { - // for timeout we need to get the value in seconds - if configurationBean.Key == util2.GetConfigKeyStr(bean.TimeOutKey) { - timeout := configurationBean.Value.(float64) - //timeout, _ := strconv.ParseFloat(configurationBean.Value.(float64), 64) - // if user ever gives the timeout in float, after conversion to int64 it will be rounded off - timeUnit := units.TimeUnitStr(configurationBean.Unit) - return int64(timeout * impl.units.GetTimeUnits()[timeUnit].ConversionFactor) +func (impl *InfraConfigServiceImpl) getInfraConfigurationForTrigger(configBeans []*v1.ConfigurationBean) (*v1.InfraConfig, error) { + var err error + infraConfiguration := &v1.InfraConfig{} + for _, configBean := range configBeans { + infraConfiguration, err = impl.infraConfigClient.OverrideInfraConfig(infraConfiguration, configBean) + if err != nil { + impl.logger.Errorw("error in overriding config", "configBean", configBean, "error", err) + return infraConfiguration, err + } } - if configurationBean.Unit == string(units.CORE) || configurationBean.Unit == string(units.BYTE) { - return fmt.Sprintf("%v", configurationBean.Value.(float64)) + return infraConfiguration, nil +} + +// getAppliedProfileForTriggerScope here we are returning the default platform configuration in case no other platform config found +func (impl *InfraConfigServiceImpl) getAppliedProfileForTriggerScope(scope *v1.Scope) (*v1.ProfileBeanDto, *v1.ProfileBeanDto, error) { + // Fetching scope-specific configurations and associated profile IDs + infraProfilesEntities, appliedProfileIds, err := impl.getInfraProfilesByScope(scope, true) + // If we got an error other than NO_PROPERTIES_FOUND_ERROR, return it + if err != nil && !errors.Is(err, infraErrors.NoPropertiesFoundError) { + impl.logger.Errorw("error in fetching configurations", "scope", scope, "error", err) + return nil, nil, err } - return fmt.Sprintf("%v%v", configurationBean.Value.(float64), configurationBean.Unit) + profilesMap, defaultProfileId, err := impl.fillConfigurationsInProfiles(infraProfilesEntities) + if err != nil { + impl.logger.Errorw("error in filling configuration in profile objects", "infraProfilesEntities", infraProfilesEntities, "error", err) + return nil, nil, err + } + defaultProfile := profilesMap[defaultProfileId] + // CASE 1: If no profileIds => we are in the "global only" scenario + if len(appliedProfileIds) == 0 { + // Return all platforms from the global config (or whichever subset you want). + return defaultProfile, defaultProfile, nil + } + // Get the profile (assuming one profileId, or adapt if multiple) + profileId := appliedProfileIds[0] + return profilesMap[profileId], defaultProfile, nil } -func (impl *InfraConfigServiceImpl) GetConfigurationUnits() map[bean.ConfigKeyStr]map[string]units.Unit { - configurationUnits := make(map[bean.ConfigKeyStr]map[string]units.Unit) - cpuUnits := make(map[string]units.Unit) - memUnits := make(map[string]units.Unit) - timeUnits := make(map[string]units.Unit) - for key, val := range impl.units.GetCpuUnits() { - cpuUnits[string(key)] = val +func (impl *InfraConfigServiceImpl) fillConfigurationsInProfiles(profiles []*repository.InfraProfileEntity) (map[int]*v1.ProfileBeanDto, int, error) { + // override profileIds with the profiles fetched from db + profileIds := make([]int, 0, len(profiles)) + for _, profile := range profiles { + profileIds = append(profileIds, profile.Id) + } + profilesMap := make(map[int]*v1.ProfileBeanDto) + defaultProfileId := 0 + for _, profile := range profiles { + profilesMap[profile.Id] = adapter.ConvertToProfileBean(profile) + if profile.Name == v1.GLOBAL_PROFILE_NAME { + defaultProfileId = profile.Id + } } - for key, val := range impl.units.GetMemoryUnits() { - memUnits[string(key)] = val + + // find the configurations for the profileIds + infraConfigurations, err := impl.infraProfileRepo.GetConfigurationsByProfileIds(profileIds) + if err != nil { + impl.logger.Errorw("error in fetching default configurations", "profileIds", profileIds, "error", err) + return nil, 0, err } - for key, val := range impl.units.GetTimeUnits() { - timeUnits[string(key)] = val + profilePlatforms, err := impl.infraProfileRepo.GetPlatformsByProfileIds(profileIds) + if err != nil { + impl.logger.Errorw("error in fetching default configurations", "profileIds", profileIds, "error", err) + return nil, 0, err } - configurationUnits[bean.CPU_REQUEST] = cpuUnits - configurationUnits[bean.CPU_LIMIT] = cpuUnits + profilePlatformMap, err := impl.infraConfigClient.ConvertToProfilePlatformMap(infraConfigurations, profilesMap, profilePlatforms) + if err != nil { + impl.logger.Errorw("error in converting profile platform map from infra configurations", "ConvertToProfilePlatformMap", infraConfigurations, "profilePlatforms", profilePlatforms, "error", err) + return nil, 0, err + } + + // map the configurations to their respective profiles + for _, profile := range profiles { + profileBean := profilesMap[profile.Id] + if profileBean.GetBuildxDriverType().IsKubernetes() { + profileBean.Configurations = profilePlatformMap[profile.Id] + } else { + configurations := profilePlatformMap[profile.Id][v1.RUNNER_PLATFORM] + profileBean.Configurations = map[string][]*v1.ConfigurationBean{v1.RUNNER_PLATFORM: configurations} + } + profilesMap[profile.Id] = profileBean + } - configurationUnits[bean.MEMORY_REQUEST] = memUnits - configurationUnits[bean.MEMORY_LIMIT] = memUnits + // fill the default configurations for each profile if any of the default configuration is missing + defaultProfile, ok := profilesMap[defaultProfileId] + if !ok { + impl.logger.Errorw("global profile not found", "defaultProfileId", defaultProfileId) + return profilesMap, defaultProfileId, errors.New("global profile not found") + } + defaultProfile, err = impl.getAppliedConfigurationsForProfile(defaultProfile, defaultProfile.GetConfigurations()) + if err != nil { + impl.logger.Errorw("error in getting applied config for defaultProfile", "defaultProfile", defaultProfile, "error", err) + return profilesMap, defaultProfileId, err + } + profilesMap[defaultProfileId] = defaultProfile + for profileId, profile := range profilesMap { + if profile.GetName() == v1.GLOBAL_PROFILE_NAME { + // skip global profile, as it is already processed + continue + } + profile, err = impl.getAppliedConfigurationsForProfile(profile, defaultProfile.GetConfigurations()) + if err != nil { + impl.logger.Errorw("error in getting applied config for profile", "profile", profile, "defaultConfigurations", defaultProfile.GetConfigurations(), "error", err) + return profilesMap, defaultProfileId, err + } + // update map with updated profile + profilesMap[profileId] = profile + } + return profilesMap, defaultProfileId, nil +} - configurationUnits[bean.TIME_OUT] = timeUnits +func (impl *InfraConfigServiceImpl) getAppliedConfigurationsForProfile(profile *v1.ProfileBeanDto, defaultConfigurationsMap map[string][]*v1.ConfigurationBean) (*v1.ProfileBeanDto, error) { + if len(profile.GetConfigurations()) == 0 { + if profile.Configurations == nil { + profile.Configurations = make(map[string][]*v1.ConfigurationBean) + } + profile.Configurations[v1.RUNNER_PLATFORM] = []*v1.ConfigurationBean{} + } + for platform := range profile.GetConfigurations() { + defaultConfigurations := impl.infraConfigClient.GetDefaultConfigurationForPlatform(platform, defaultConfigurationsMap) + updatedProfileConfigurations, err := impl.getAppliedConfigurationsForPlatform(platform, profile.GetConfigurations()[platform], defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in getting missing configurations from default", "platform", platform, "profileConfigurations", profile.GetConfigurations()[platform], "defaultConfigurations", defaultConfigurations, "error", err) + return profile, err + } + profile = profile.SetPlatformConfigurations(platform, updatedProfileConfigurations) + } + return profile, nil +} - return configurationUnits +func (impl *InfraConfigServiceImpl) getAppliedConfigurationsForPlatform(platform string, profileConfigurations, defaultConfigurations []*v1.ConfigurationBean) ([]*v1.ConfigurationBean, error) { + updatedProfileConfigurations := make([]*v1.ConfigurationBean, 0) + // If the profile has configurations, then check for missing configurations, + // Add the missing configurations to the profile + for supportedConfigKey := range util.GetConfigKeysMapForPlatform(platform) { + index, found := sliceUtil.Find(profileConfigurations, func(profileConfiguration *v1.ConfigurationBean) bool { + return profileConfiguration.Key == supportedConfigKey + }) + if !found { + // configuration not found, process default configuration + updatedProfileConfiguration, err := impl.infraConfigClient.MergeInfraConfigurations(supportedConfigKey, nil, defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in merging infra configurations", "defaultConfigurations", defaultConfigurations, "error", err) + return profileConfigurations, err + } + if updatedProfileConfiguration != nil { + updatedProfileConfigurations = append(updatedProfileConfigurations, updatedProfileConfiguration) + } + } else { + // configuration found, merge it with default configuration + updatedProfileConfiguration, err := impl.infraConfigClient.MergeInfraConfigurations(supportedConfigKey, profileConfigurations[index], defaultConfigurations) + if err != nil { + impl.logger.Errorw("error in merging infra configurations", "profileConfiguration", profileConfigurations[index], "defaultConfigurations", defaultConfigurations, "error", err) + return profileConfigurations, err + } + if updatedProfileConfiguration != nil { + updatedProfileConfigurations = append(updatedProfileConfigurations, updatedProfileConfiguration) + } + } + } + return updatedProfileConfigurations, nil } -func (impl *InfraConfigServiceImpl) validate(profileToUpdate *bean.ProfileBeanDto, defaultProfile *bean.ProfileBeanDto) error { +func (impl *InfraConfigServiceImpl) createGlobalProfile(tx *pg.Tx) (*repository.InfraProfileEntity, error) { + // if default profiles not found then create default profile + defaultProfile := &repository.InfraProfileEntity{ + Name: v1.GLOBAL_PROFILE_NAME, + Description: "", + BuildxDriverType: impl.getDefaultBuildxDriverType(), + Active: true, + AuditLog: sql.NewDefaultAuditLog(1), + } + err := impl.infraProfileRepo.CreateProfile(tx, defaultProfile) + if err != nil { + impl.logger.Errorw("error in creation of global profile", "error", err) + return nil, err + } + return defaultProfile, nil +} - err := impl.validateInfraConfig(profileToUpdate, defaultProfile) +func (impl *InfraConfigServiceImpl) getInfraProfilesByScope(scope *v1.Scope, includeDefault bool) ([]*repository.InfraProfileEntity, []int, error) { + profileIds, err := impl.getInfraProfileIdsByScope(scope) if err != nil { - err = errors.Wrap(err, bean.PayloadValidationError) - return err + impl.logger.Errorw("error in fetching profile ids by scope", "scope", scope, "error", err) + return nil, profileIds, err } - return nil + infraProfilesEntities, err := impl.infraProfileRepo.GetProfileListByIds(profileIds, includeDefault) + if err != nil { + impl.logger.Errorw("error in fetching profile entities by ids", "scope", scope, "profileIds", profileIds, "error", err) + return nil, profileIds, err + } + return infraProfilesEntities, profileIds, err } diff --git a/pkg/infraConfig/service/infraConfigService_ent.go b/pkg/infraConfig/service/infraConfigService_ent.go new file mode 100644 index 0000000000..f8105b05a2 --- /dev/null +++ b/pkg/infraConfig/service/infraConfigService_ent.go @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package service + +import ( + v1 "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" + "github.com/go-pg/pg" +) + +type InfraConfigServiceEnt interface { +} + +func (impl *InfraConfigServiceImpl) isMigrationRequired() (bool, error) { + return true, nil +} + +func (impl *InfraConfigServiceImpl) markMigrationComplete(tx *pg.Tx) error { + return nil +} + +func (impl *InfraConfigServiceImpl) resolveScopeVariablesForAppliedProfile(scope resourceQualifiers.Scope, appliedProfileConfig *v1.ProfileBeanDto) (*v1.ProfileBeanDto, map[string]map[string]string, error) { + return appliedProfileConfig, nil, nil +} + +func (impl *InfraConfigServiceImpl) updateBuildxDriverTypeInExistingProfiles(tx *pg.Tx) error { + return nil +} + +func (impl *InfraConfigServiceImpl) getCreatableK8sDriverConfigs(profileId int, envConfigs []*repository.InfraProfileConfigurationEntity) ([]*repository.InfraProfileConfigurationEntity, error) { + return make([]*repository.InfraProfileConfigurationEntity, 0), nil +} + +func (impl *InfraConfigServiceImpl) getDefaultBuildxDriverType() v1.BuildxDriver { + return v1.BuildxDockerContainerDriver +} + +func (impl *InfraConfigServiceImpl) getInfraProfileIdsByScope(scope *v1.Scope) ([]int, error) { + // for OSS, user can't create infra profiles so no need to fetch infra profiles + return make([]int, 0), nil +} diff --git a/pkg/infraConfig/units/bean/cpu_unit_types.go b/pkg/infraConfig/units/bean/cpu_unit_types.go new file mode 100644 index 0000000000..e9f4b8551f --- /dev/null +++ b/pkg/infraConfig/units/bean/cpu_unit_types.go @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bean + +import ( + serviceBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" +) + +type CPUUnitStr string + +const ( + CORE CPUUnitStr = "Core" + MILLI CPUUnitStr = "m" +) + +func (cpuUnitStr CPUUnitStr) GetUnitSuffix() UnitType { + switch cpuUnitStr { + case CORE: + return Core + case MILLI: + return Milli + default: + return Core + } +} + +func (cpuUnitStr CPUUnitStr) GetUnit() (serviceBean.Unit, bool) { + cpuUnits := GetCPUUnit() + cpuUnit, exists := cpuUnits[cpuUnitStr] + return cpuUnit, exists +} + +func (cpuUnitStr CPUUnitStr) String() string { + return string(cpuUnitStr) +} + +func GetCPUUnit() map[CPUUnitStr]serviceBean.Unit { + return map[CPUUnitStr]serviceBean.Unit{ + MILLI: { + Name: string(MILLI), + ConversionFactor: 1e-3, + }, + CORE: { + Name: string(CORE), + ConversionFactor: 1, + }, + } +} diff --git a/pkg/infraConfig/units/bean/memory_unit_type.go b/pkg/infraConfig/units/bean/memory_unit_type.go new file mode 100644 index 0000000000..93d7a33f57 --- /dev/null +++ b/pkg/infraConfig/units/bean/memory_unit_type.go @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bean + +import ( + serviceBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" +) + +type MemoryUnitStr string + +const ( + MILLIBYTE MemoryUnitStr = "m" + BYTE MemoryUnitStr = "byte" + KIBYTE MemoryUnitStr = "Ki" + MIBYTE MemoryUnitStr = "Mi" + GIBYTE MemoryUnitStr = "Gi" + TIBYTE MemoryUnitStr = "Ti" + PIBYTE MemoryUnitStr = "Pi" + EIBYTE MemoryUnitStr = "Ei" + KBYTE MemoryUnitStr = "k" + MBYTE MemoryUnitStr = "M" + GBYTE MemoryUnitStr = "G" + TBYTE MemoryUnitStr = "T" + PBYTE MemoryUnitStr = "P" + EBYTE MemoryUnitStr = "E" +) + +func (memoryUnitStr MemoryUnitStr) GetUnitSuffix() UnitType { + switch memoryUnitStr { + case BYTE: + return Byte + case KIBYTE: + return KiByte + case MIBYTE: + return MiByte + case GIBYTE: + return GiByte + case TIBYTE: + return TiByte + case PIBYTE: + return PiByte + case EIBYTE: + return EiByte + case KBYTE: + return K + case MBYTE: + return M + case GBYTE: + return G + case TBYTE: + return T + case PBYTE: + return P + case EBYTE: + return E + default: + return Byte + } +} + +func (memoryUnitStr MemoryUnitStr) GetUnit() (serviceBean.Unit, bool) { + memoryUnits := GetMemoryUnit() + memoryUnit, exists := memoryUnits[memoryUnitStr] + return memoryUnit, exists +} + +func (memoryUnitStr MemoryUnitStr) String() string { + return string(memoryUnitStr) +} + +func GetMemoryUnit() map[MemoryUnitStr]serviceBean.Unit { + return map[MemoryUnitStr]serviceBean.Unit{ + MILLIBYTE: { + Name: string(MILLIBYTE), + ConversionFactor: 1e-3, + }, + BYTE: { + Name: string(BYTE), + ConversionFactor: 1, + }, + KBYTE: { + Name: string(KBYTE), + ConversionFactor: 1000, + }, + MBYTE: { + Name: string(MBYTE), + ConversionFactor: 1000000, + }, + GBYTE: { + Name: string(GBYTE), + ConversionFactor: 1000000000, + }, + TBYTE: { + Name: string(TBYTE), + ConversionFactor: 1000000000000, + }, + PBYTE: { + Name: string(PBYTE), + ConversionFactor: 1000000000000000, + }, + EBYTE: { + Name: string(EBYTE), + ConversionFactor: 1000000000000000000, + }, + KIBYTE: { + Name: string(KIBYTE), + ConversionFactor: 1024, + }, + MIBYTE: { + Name: string(MIBYTE), + ConversionFactor: 1024 * 1024, + }, + GIBYTE: { + Name: string(GIBYTE), + ConversionFactor: 1024 * 1024 * 1024, + }, + TIBYTE: { + Name: string(TIBYTE), + ConversionFactor: 1024 * 1024 * 1024 * 1024, + }, + PIBYTE: { + Name: string(PIBYTE), + ConversionFactor: 1024 * 1024 * 1024 * 1024 * 1024, + }, + EIBYTE: { + Name: string(EIBYTE), + ConversionFactor: 1024 * 1024 * 1024 * 1024 * 1024 * 1024, + }, + } +} diff --git a/pkg/infraConfig/units/bean/no_unit_type.go b/pkg/infraConfig/units/bean/no_unit_type.go new file mode 100644 index 0000000000..5b39781223 --- /dev/null +++ b/pkg/infraConfig/units/bean/no_unit_type.go @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bean + +import serviceBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + +type NoUnitStr string + +const ( + NoUnit NoUnitStr = "" +) + +// GetUnitSuffix returns the UnitSuffix for NoUnit (just return 20 as it represents no unit) +func (noUnitStr NoUnitStr) GetUnitSuffix() UnitType { + switch noUnitStr { + case NoUnit: + return NoSuffix + default: + return NoSuffix + } +} + +func (noUnitStr NoUnitStr) GetUnit() (serviceBean.Unit, bool) { + noUnits := GetNoUnit() + noUnit, exists := noUnits[noUnitStr] + return noUnit, exists +} + +func (noUnitStr NoUnitStr) String() string { + return string(noUnitStr) +} + +func GetNoUnit() map[NoUnitStr]serviceBean.Unit { + return map[NoUnitStr]serviceBean.Unit{ + NoUnit: { + Name: "NoUnit", + ConversionFactor: 0, + }, + } +} diff --git a/pkg/infraConfig/units/bean/time_unit_types.go b/pkg/infraConfig/units/bean/time_unit_types.go new file mode 100644 index 0000000000..e3029fa39a --- /dev/null +++ b/pkg/infraConfig/units/bean/time_unit_types.go @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bean + +import ( + serviceBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" +) + +type TimeUnitStr string + +const ( + SecondStr TimeUnitStr = "Seconds" + MinuteStr TimeUnitStr = "Minutes" + HourStr TimeUnitStr = "Hours" +) + +func (timeUnitStr TimeUnitStr) GetUnitSuffix() UnitType { + switch timeUnitStr { + case SecondStr: + return Second + case MinuteStr: + return Minute + case HourStr: + return Hour + default: + return Second + } +} + +func (timeUnitStr TimeUnitStr) GetUnit() (serviceBean.Unit, bool) { + timeUnits := GetTimeUnit() + timeUnit, exists := timeUnits[timeUnitStr] + return timeUnit, exists +} + +func (timeUnitStr TimeUnitStr) String() string { + return string(timeUnitStr) +} + +func GetTimeUnit() map[TimeUnitStr]serviceBean.Unit { + return map[TimeUnitStr]serviceBean.Unit{ + SecondStr: { + Name: string(SecondStr), + ConversionFactor: 1, + }, + MinuteStr: { + Name: string(MinuteStr), + ConversionFactor: 60, + }, + HourStr: { + Name: string(HourStr), + ConversionFactor: 3600, + }, + } +} diff --git a/pkg/infraConfig/units/bean/unit_types.go b/pkg/infraConfig/units/bean/unit_types.go new file mode 100644 index 0000000000..4420a2fdfe --- /dev/null +++ b/pkg/infraConfig/units/bean/unit_types.go @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bean + +import ( + serviceBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" +) + +// memory units +// Ei, Pi, Ti, Gi, Mi, Ki +// E, P, T, G, M, k, m + +type UnitType int + +const ( + Byte UnitType = 1 + KiByte UnitType = 2 // 1024 + MiByte UnitType = 3 + GiByte UnitType = 4 + TiByte UnitType = 5 + PiByte UnitType = 6 + EiByte UnitType = 7 + K UnitType = 8 // 1000 + M UnitType = 9 + G UnitType = 10 + T UnitType = 11 + P UnitType = 12 + E UnitType = 13 + Core UnitType = 14 // CPU cores + Milli UnitType = 15 + Second UnitType = 16 + Minute UnitType = 17 + Hour UnitType = 18 + MilliByte UnitType = 19 + NoSuffix UnitType = 20 +) + +func (unitType UnitType) GetNoUnitStr() NoUnitStr { + return NoUnit +} + +func (unitType UnitType) GetCPUUnitStr() CPUUnitStr { + switch unitType { + case Core: + return CORE + case Milli: + return MILLI + default: + return CORE + } +} + +func (unitType UnitType) GetMemoryUnitStr() MemoryUnitStr { + switch unitType { + case MilliByte: + return MILLIBYTE + case Byte: + return BYTE + case KiByte: + return KIBYTE + case MiByte: + return MIBYTE + case GiByte: + return GIBYTE + case TiByte: + return TIBYTE + case PiByte: + return PIBYTE + case EiByte: + return EIBYTE + case K: + return KBYTE + case M: + return MBYTE + case G: + return GBYTE + case T: + return TBYTE + case P: + return PBYTE + case E: + return EBYTE + default: + return BYTE + } +} + +func (unitType UnitType) GetTimeUnitStr() TimeUnitStr { + switch unitType { + case Second: + return SecondStr + case Minute: + return MinuteStr + case Hour: + return HourStr + default: + return SecondStr + } +} + +type ParsedValue struct { + valueString string + unitType UnitType +} + +func NewParsedValue() *ParsedValue { + return &ParsedValue{} +} + +func (p *ParsedValue) WithValueString(value string) *ParsedValue { + p.valueString = value + return p +} + +func (p *ParsedValue) WithUnit(unit UnitType) *ParsedValue { + p.unitType = unit + return p +} + +func (p *ParsedValue) GetValueString() string { + return p.valueString +} + +func (p *ParsedValue) GetUnitType() UnitType { + return p.unitType +} + +type ConfigValue[T any] struct { + Unit serviceBean.Unit + Value T +} + +func (c *ConfigValue[_]) IsEmpty() bool { + return c == nil +} + +func NewConfigValue[T any](unit serviceBean.Unit, value T) *ConfigValue[T] { + return &ConfigValue[T]{ + Unit: unit, + Value: value, + } +} diff --git a/pkg/infraConfig/units/cpu_unit.go b/pkg/infraConfig/units/cpu_unit.go new file mode 100644 index 0000000000..f560396440 --- /dev/null +++ b/pkg/infraConfig/units/cpu_unit.go @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package units + +import ( + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/errors" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" + globalUtil "github.com/devtron-labs/devtron/util" + "go.uber.org/zap" + "net/http" + "strconv" +) + +type CPUUnitFactory struct { + logger *zap.SugaredLogger + cpuUnits map[unitsBean.CPUUnitStr]v1.Unit +} + +func NewCPUUnitFactory(logger *zap.SugaredLogger) *CPUUnitFactory { + return &CPUUnitFactory{ + logger: logger, + cpuUnits: unitsBean.GetCPUUnit(), + } +} + +func (c *CPUUnitFactory) GetAllUnits() map[string]v1.Unit { + cpuUnits := c.cpuUnits + units := make(map[string]v1.Unit) + for key, value := range cpuUnits { + units[string(key)] = value + } + return units +} + +func (c *CPUUnitFactory) GetDefaultUnitSuffix() string { + var defaultUnit unitsBean.UnitType + return defaultUnit.GetCPUUnitStr().String() +} + +func (c *CPUUnitFactory) ParseValAndUnit(val float64, unitType unitsBean.UnitType) (*unitsBean.ParsedValue, error) { + return unitsBean.NewParsedValue(). + WithValueString(strconv.FormatFloat(val, 'f', -1, 64)). + WithUnit(unitType), nil +} + +func (c *CPUUnitFactory) GetValue(valueString string) (float64, error) { + // Convert string to float64 and truncate to 2 decimal places + valueFloat, err := strconv.ParseFloat(valueString, 64) + if err != nil { + return 0, err + } + truncateValue := globalUtil.TruncateFloat(valueFloat, 2) + return truncateValue, nil +} + +func (c *CPUUnitFactory) Validate(cpuConfig *v1.GenericConfigurationBean[float64]) (*unitsBean.ConfigValue[float64], error) { + cpuUnitSuffix := unitsBean.CPUUnitStr(cpuConfig.Unit) + cpuConfigUnit, ok := cpuUnitSuffix.GetUnit() + if !ok { + errMsg := errors.InvalidUnitFound(cpuConfig.Unit, cpuConfig.Key) + return nil, util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + return unitsBean.NewConfigValue(cpuConfigUnit, cpuConfig.Value), nil +} diff --git a/pkg/infraConfig/units/memory_unit.go b/pkg/infraConfig/units/memory_unit.go new file mode 100644 index 0000000000..43b88cabd5 --- /dev/null +++ b/pkg/infraConfig/units/memory_unit.go @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package units + +import ( + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/errors" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" + globalUtil "github.com/devtron-labs/devtron/util" + "go.uber.org/zap" + "net/http" + "strconv" +) + +type MemoryUnitFactory struct { + logger *zap.SugaredLogger + memoryUnits map[unitsBean.MemoryUnitStr]v1.Unit +} + +func NewMemoryUnitFactory(logger *zap.SugaredLogger) *MemoryUnitFactory { + return &MemoryUnitFactory{ + logger: logger, + memoryUnits: unitsBean.GetMemoryUnit(), + } +} + +func (m *MemoryUnitFactory) GetAllUnits() map[string]v1.Unit { + memoryUnits := m.memoryUnits + units := make(map[string]v1.Unit) + for key, value := range memoryUnits { + units[string(key)] = value + } + return units +} + +func (m *MemoryUnitFactory) GetDefaultUnitSuffix() string { + var defaultUnit unitsBean.UnitType + return defaultUnit.GetMemoryUnitStr().String() +} + +func (m *MemoryUnitFactory) ParseValAndUnit(val float64, unitType unitsBean.UnitType) (*unitsBean.ParsedValue, error) { + return unitsBean.NewParsedValue(). + WithValueString(strconv.FormatFloat(val, 'f', -1, 64)). + WithUnit(unitType), nil +} + +func (m *MemoryUnitFactory) GetValue(valueString string) (float64, error) { + // Convert string to float64 and truncate to 2 decimal places + valueFloat, err := strconv.ParseFloat(valueString, 64) + if err != nil { + return 0, err + } + truncateValue := globalUtil.TruncateFloat(valueFloat, 2) + return truncateValue, nil +} + +func (m *MemoryUnitFactory) Validate(memConfig *v1.GenericConfigurationBean[float64]) (*unitsBean.ConfigValue[float64], error) { + memConfigUnitSuffix := unitsBean.MemoryUnitStr(memConfig.Unit) + memConfigUnit, ok := memConfigUnitSuffix.GetUnit() + if !ok { + errMsg := errors.InvalidUnitFound(memConfig.Unit, memConfig.Key) + return nil, util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + return unitsBean.NewConfigValue(memConfigUnit, memConfig.Value), nil +} diff --git a/pkg/infraConfig/units/time_unit.go b/pkg/infraConfig/units/time_unit.go new file mode 100644 index 0000000000..504fd26577 --- /dev/null +++ b/pkg/infraConfig/units/time_unit.go @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package units + +import ( + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/errors" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" + "go.uber.org/zap" + "math" + "net/http" + "strconv" +) + +type TimeUnitFactory struct { + logger *zap.SugaredLogger + timeUnits map[unitsBean.TimeUnitStr]v1.Unit +} + +func NewTimeUnitFactory(logger *zap.SugaredLogger) *TimeUnitFactory { + return &TimeUnitFactory{ + logger: logger, + timeUnits: unitsBean.GetTimeUnit(), + } +} + +func (t *TimeUnitFactory) GetAllUnits() map[string]v1.Unit { + timeUnits := t.timeUnits + units := make(map[string]v1.Unit) + for key, value := range timeUnits { + units[string(key)] = value + } + return units +} + +func (t *TimeUnitFactory) GetDefaultUnitSuffix() string { + var defaultUnit unitsBean.UnitType + return defaultUnit.GetTimeUnitStr().String() +} + +func (t *TimeUnitFactory) ParseValAndUnit(val float64, unitType unitsBean.UnitType) (*unitsBean.ParsedValue, error) { + modifiedValue := math.Min(math.Floor(val), math.MaxInt64) + return unitsBean.NewParsedValue(). + WithValueString(strconv.FormatInt(int64(modifiedValue), 10)). + WithUnit(unitType), nil +} + +func (t *TimeUnitFactory) GetValue(valueString string) (float64, error) { + // Convert string to float64 and ensure it's within integer range + valueFloat, err := strconv.ParseFloat(valueString, 64) + if err != nil { + return 0, err + } + modifiedValue := math.Min(math.Floor(valueFloat), math.MaxInt64) + return modifiedValue, nil +} + +func (t *TimeUnitFactory) Validate(timeConfig *v1.GenericConfigurationBean[float64]) (*unitsBean.ConfigValue[float64], error) { + if timeConfig == nil { + return &unitsBean.ConfigValue[float64]{}, nil + } + timeoutUnitSuffix := unitsBean.TimeUnitStr(timeConfig.Unit) + timeoutUnit, ok := timeoutUnitSuffix.GetUnit() + if !ok { + errMsg := errors.InvalidUnitFound(timeConfig.Unit, timeConfig.Key) + return nil, util.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + return unitsBean.NewConfigValue(timeoutUnit, timeConfig.Value), nil +} diff --git a/pkg/infraConfig/units/units.go b/pkg/infraConfig/units/units.go index 1c19b72576..5d65f83e53 100644 --- a/pkg/infraConfig/units/units.go +++ b/pkg/infraConfig/units/units.go @@ -17,450 +17,30 @@ package units import ( - "github.com/devtron-labs/devtron/util" - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/api/resource" - "strconv" - "strings" + "encoding/json" + "fmt" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" ) -// memory units -// Ei, Pi, Ti, Gi, Mi, Ki -// E, P, T, G, M, k, m - -type UnitSuffix int - -const ( - Byte UnitSuffix = 1 - KiByte UnitSuffix = 2 // 1024 - MiByte UnitSuffix = 3 - GiByte UnitSuffix = 4 - TiByte UnitSuffix = 5 - PiByte UnitSuffix = 6 - EiByte UnitSuffix = 7 - K UnitSuffix = 8 // 1000 - M UnitSuffix = 9 - G UnitSuffix = 10 - T UnitSuffix = 11 - P UnitSuffix = 12 - E UnitSuffix = 13 - Core UnitSuffix = 14 // CPU cores - Milli UnitSuffix = 15 - Second UnitSuffix = 16 - Minute UnitSuffix = 17 - Hour UnitSuffix = 18 - MilliByte UnitSuffix = 19 -) - -type UnitStr interface { - CPUUnitStr | MemoryUnitStr | TimeUnitStr -} - -type CPUUnitStr string - -func (cpuUnit UnitSuffix) GetCPUUnitStr() CPUUnitStr { - switch cpuUnit { - case Core: - return CORE - case Milli: - return MILLI - default: - return CORE - } -} - -func (cpuUnitStr CPUUnitStr) GetCPUUnit() UnitSuffix { - switch cpuUnitStr { - case CORE: - return Core - case MILLI: - return Milli - default: - return Core - } -} - -const ( - CORE CPUUnitStr = "Core" - MILLI CPUUnitStr = "m" -) - -type MemoryUnitStr string - -const ( - MILLIBYTE MemoryUnitStr = "m" - BYTE MemoryUnitStr = "byte" - KIBYTE MemoryUnitStr = "Ki" - MIBYTE MemoryUnitStr = "Mi" - GIBYTE MemoryUnitStr = "Gi" - TIBYTE MemoryUnitStr = "Ti" - PIBYTE MemoryUnitStr = "Pi" - EIBYTE MemoryUnitStr = "Ei" - KBYTE MemoryUnitStr = "k" - MBYTE MemoryUnitStr = "M" - GBYTE MemoryUnitStr = "G" - TBYTE MemoryUnitStr = "T" - PBYTE MemoryUnitStr = "P" - EBYTE MemoryUnitStr = "E" -) - -func (memoryUnit UnitSuffix) GetMemoryUnitStr() MemoryUnitStr { - switch memoryUnit { - case MilliByte: - return MILLIBYTE - case Byte: - return BYTE - case KiByte: - return KIBYTE - case MiByte: - return MIBYTE - case GiByte: - return GIBYTE - case TiByte: - return TIBYTE - case PiByte: - return PIBYTE - case EiByte: - return EIBYTE - case K: - return KBYTE - case M: - return MBYTE - case G: - return GBYTE - case T: - return TBYTE - case P: - return PBYTE - case E: - return EBYTE - default: - return BYTE - } -} - -func (memoryUnitStr MemoryUnitStr) GetMemoryUnit() UnitSuffix { - switch memoryUnitStr { - case BYTE: - return Byte - case KIBYTE: - return KiByte - case MIBYTE: - return MiByte - case GIBYTE: - return GiByte - case TIBYTE: - return TiByte - case PIBYTE: - return PiByte - case EIBYTE: - return EiByte - case KBYTE: - return K - case MBYTE: - return M - case GBYTE: - return G - case TBYTE: - return T - case PBYTE: - return P - case EBYTE: - return E - default: - return Byte - } +type UnitService[T any] interface { + GetAllUnits() map[string]v1.Unit + GetDefaultUnitSuffix() string + ParseValAndUnit(val T, unitType unitsBean.UnitType) (*unitsBean.ParsedValue, error) + Validate(configuration *v1.GenericConfigurationBean[T]) (*unitsBean.ConfigValue[T], error) } -type TimeUnitStr string - -const ( - SecondStr TimeUnitStr = "Seconds" - MinuteStr TimeUnitStr = "Minutes" - HourStr TimeUnitStr = "Hours" -) - -func (timeUnit UnitSuffix) GetTimeUnitStr() TimeUnitStr { - switch timeUnit { - case Second: - return SecondStr - case Minute: - return MinuteStr - case Hour: - return HourStr - default: - return SecondStr - } +type UnitStrService interface { + GetUnitSuffix() unitsBean.UnitType + GetUnit() (v1.Unit, bool) + String() string + unitsBean.CPUUnitStr | unitsBean.MemoryUnitStr | unitsBean.TimeUnitStr | unitsBean.NoUnitStr } -func (timeUnitStr TimeUnitStr) GetTimeUnit() UnitSuffix { - switch timeUnitStr { - case SecondStr: - return Second - case MinuteStr: - return Minute - case HourStr: - return Hour - default: - return Second - } -} - -type Units struct { - cpuUnits map[CPUUnitStr]Unit - memoryUnits map[MemoryUnitStr]Unit - timeUnits map[TimeUnitStr]Unit -} - -func NewUnits() *Units { - cpuUnits := map[CPUUnitStr]Unit{ - MILLI: { - Name: string(MILLI), - ConversionFactor: 1e-3, - }, - CORE: { - Name: string(CORE), - ConversionFactor: 1, - }, - } - - memoryUnits := map[MemoryUnitStr]Unit{ - MILLIBYTE: { - Name: string(MILLIBYTE), - ConversionFactor: 1e-3, - }, - BYTE: { - Name: string(BYTE), - ConversionFactor: 1, - }, - KBYTE: { - Name: string(KBYTE), - ConversionFactor: 1000, - }, - MBYTE: { - Name: string(MBYTE), - ConversionFactor: 1000000, - }, - GBYTE: { - Name: string(GBYTE), - ConversionFactor: 1000000000, - }, - TBYTE: { - Name: string(TBYTE), - ConversionFactor: 1000000000000, - }, - PBYTE: { - Name: string(PBYTE), - ConversionFactor: 1000000000000000, - }, - EBYTE: { - Name: string(EBYTE), - ConversionFactor: 1000000000000000000, - }, - KIBYTE: { - Name: string(KIBYTE), - ConversionFactor: 1024, - }, - MIBYTE: { - Name: string(MIBYTE), - ConversionFactor: 1024 * 1024, - }, - GIBYTE: { - Name: string(GIBYTE), - ConversionFactor: 1024 * 1024 * 1024, - }, - TIBYTE: { - Name: string(TIBYTE), - ConversionFactor: 1024 * 1024 * 1024 * 1024, - }, - PIBYTE: { - Name: string(PIBYTE), - ConversionFactor: 1024 * 1024 * 1024 * 1024 * 1024, - }, - EIBYTE: { - Name: string(EIBYTE), - ConversionFactor: 1024 * 1024 * 1024 * 1024 * 1024 * 1024, - }, - } - - timeUnits := map[TimeUnitStr]Unit{ - SecondStr: { - Name: string(SecondStr), - ConversionFactor: 1, - }, - MinuteStr: { - Name: string(MinuteStr), - ConversionFactor: 60, - }, - HourStr: { - Name: string(HourStr), - ConversionFactor: 3600, - }, - } - return &Units{ - cpuUnits: cpuUnits, - memoryUnits: memoryUnits, - timeUnits: timeUnits, - } -} - -func (u *Units) GetCpuUnits() map[CPUUnitStr]Unit { - return u.cpuUnits -} - -func (u *Units) GetMemoryUnits() map[MemoryUnitStr]Unit { - return u.memoryUnits -} - -func (u *Units) GetTimeUnits() map[TimeUnitStr]Unit { - return u.timeUnits -} - -// Unit represents unit of a configuration -type Unit struct { - // Name is unit name - Name string `json:"name"` - // ConversionFactor is used to convert this unit to the base unit - // if ConversionFactor is 1, then this is the base unit - ConversionFactor float64 `json:"conversionFactor"` -} - -// ParseValAndUnit parses the quantity which have number values string and returns the value and unit -// returns error if parsing fails -func ParseValAndUnit(quantity string) (float64, string, error) { - positive, _, num, denom, suffix, err := ParseQuantityString(quantity) +func parseJsonValueToString[T any](customValue T) (string, error) { + jsonValue, err := json.Marshal(customValue) if err != nil { - return 0, "", err - } - if !positive { - return 0, "", errors.New("negative value not allowed for cpu limits") - } - valStr := num - if denom != "" { - valStr = num + "." + denom - } - - val, err := strconv.ParseFloat(valStr, 64) - - // currently we are not supporting exponential values upto 2 decimals - val = util.TruncateFloat(val, 2) - return val, suffix, err -} - -// ParseQuantityString is a fast scanner for quantity values. -// this parsing is only for cpu and mem resources -func ParseQuantityString(str string) (positive bool, value, num, denom, suffix string, err error) { - positive = true - pos := 0 - end := len(str) - - // handle leading sign - if pos < end { - switch str[0] { - case '-': - positive = false - pos++ - case '+': - pos++ - } - } - - // strip leading zeros -Zeroes: - for i := pos; ; i++ { - if i >= end { - num = "0" - value = num - return - } - switch str[i] { - case '0': - pos++ - default: - break Zeroes - } - } - - // extract the numerator -Num: - for i := pos; ; i++ { - if i >= end { - num = str[pos:end] - value = str[0:end] - return - } - switch str[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - num = str[pos:i] - pos = i - break Num - } - } - - // if we stripped all numerator positions, always return 0 - if len(num) == 0 { - num = "0" - } - - // handle a denominator - if pos < end && str[pos] == '.' { - pos++ - Denom: - for i := pos; ; i++ { - if i >= end { - denom = str[pos:end] - value = str[0:end] - return - } - switch str[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - denom = str[pos:i] - pos = i - break Denom - } - } - // TODO: we currently allow 1.G, but we may not want to in the future. - // if len(denom) == 0 { - // err = ErrFormatWrong - // return - // } - } - value = str[0:pos] - - // grab the elements of the suffix - suffixStart := pos - for i := pos; ; i++ { - if i >= end { - suffix = str[suffixStart:end] - return - } - if !strings.ContainsAny(str[i:i+1], "eEinumkKMGTP") { - pos = i - break - } - } - if pos < end { - switch str[pos] { - case '-', '+': - pos++ - } - } -Suffix: - for i := pos; ; i++ { - if i >= end { - suffix = str[suffixStart:end] - return - } - switch str[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - break Suffix - } + return "", fmt.Errorf("failed to marshal: %w", err) } - // we encountered a non decimal in the Suffix loop, but the last character - // was not a valid exponent - err = resource.ErrFormatWrong - return + return string(jsonValue), nil } diff --git a/pkg/infraConfig/util/utils.go b/pkg/infraConfig/util/utils.go index 2f02b2bb6c..ff79e1704c 100644 --- a/pkg/infraConfig/util/utils.go +++ b/pkg/infraConfig/util/utils.go @@ -14,207 +14,201 @@ * limitations under the License. */ -package utils +package util import ( - "errors" "fmt" - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" - "github.com/devtron-labs/devtron/pkg/infraConfig/units" - util2 "github.com/devtron-labs/devtron/util" - "math" - "reflect" - "strconv" + globalUtil "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + unitsBean "github.com/devtron-labs/devtron/pkg/infraConfig/units/bean" + "net/http" + "slices" "strings" ) +func CreateConfigKeyPlatformMap(configs []*repository.InfraProfileConfigurationEntity) map[v1.ConfigKeyPlatformKey]bool { + configMap := make(map[v1.ConfigKeyPlatformKey]bool, len(configs)) + for _, config := range configs { + platform := config.ProfilePlatformMapping.Platform + if platform == "" { + platform = v1.RUNNER_PLATFORM + } + configMap[v1.ConfigKeyPlatformKey{Key: config.Key, Platform: platform}] = true + } + return configMap +} + // GetUnitSuffix loosely typed method to get the unit suffix using the unitKey type -func GetUnitSuffix(unitKey bean.ConfigKeyStr, unitStr string) units.UnitSuffix { +func GetUnitSuffix(unitKey v1.ConfigKeyStr, unitStr string) unitsBean.UnitType { switch unitKey { - case bean.CPU_LIMIT, bean.CPU_REQUEST: - return units.CPUUnitStr(unitStr).GetCPUUnit() - case bean.MEMORY_LIMIT, bean.MEMORY_REQUEST: - return units.MemoryUnitStr(unitStr).GetMemoryUnit() + case v1.CPU_LIMIT, v1.CPU_REQUEST: + return unitsBean.CPUUnitStr(unitStr).GetUnitSuffix() + case v1.MEMORY_LIMIT, v1.MEMORY_REQUEST: + return unitsBean.MemoryUnitStr(unitStr).GetUnitSuffix() + case v1.TIME_OUT: + return unitsBean.TimeUnitStr(unitStr).GetUnitSuffix() + case v1.TOLERATIONS, v1.NODE_SELECTOR, v1.SECRET, v1.CONFIG_MAP: + return unitsBean.NoUnitStr(unitStr).GetUnitSuffix() + default: + return unitsBean.NoUnitStr(unitStr).GetUnitSuffix() } - return units.TimeUnitStr(unitStr).GetTimeUnit() } // GetUnitSuffixStr loosely typed method to get the unit suffix using the unitKey type -func GetUnitSuffixStr(unitKey bean.ConfigKey, unit units.UnitSuffix) string { +func GetUnitSuffixStr(unitKey v1.ConfigKey, unit unitsBean.UnitType) string { switch unitKey { - case bean.CPULimitKey, bean.CPURequestKey: - return string(unit.GetCPUUnitStr()) - case bean.MemoryLimitKey, bean.MemoryRequestKey: - return string(unit.GetMemoryUnitStr()) + case v1.CPULimitKey, v1.CPURequestKey: + return unit.GetCPUUnitStr().String() + case v1.MemoryLimitKey, v1.MemoryRequestKey: + return unit.GetMemoryUnitStr().String() + case v1.TimeOutKey: + return unit.GetTimeUnitStr().String() + case v1.TolerationsKey, v1.NodeSelectorKey, v1.SecretKey, v1.ConfigMapKey: + return unit.GetNoUnitStr().String() + } + return unit.GetNoUnitStr().String() +} + +// GetDefaultConfigKeysMapV0 returns a map of default config keys +func GetDefaultConfigKeysMapV0() map[v1.ConfigKeyStr]bool { + return map[v1.ConfigKeyStr]bool{ + v1.CPU_LIMIT: true, + v1.CPU_REQUEST: true, + v1.MEMORY_LIMIT: true, + v1.MEMORY_REQUEST: true, + v1.TIME_OUT: true, + // v1.NODE_SELECTOR is added in V1, but maintained for backward compatibility + v1.NODE_SELECTOR: true, + // v1.TOLERATIONS is added in V1, but maintained for backward compatibility + v1.TOLERATIONS: true, + } +} + +// GetConfigKeysMapForPlatform returns a map of config keys supported for a given platform +func GetConfigKeysMapForPlatform(platform string) v1.InfraConfigKeys { + defaultConfigKeys := map[v1.ConfigKeyStr]bool{ + v1.CPU_LIMIT: true, + v1.CPU_REQUEST: true, + v1.MEMORY_LIMIT: true, + v1.MEMORY_REQUEST: true, + } + if platform == v1.RUNNER_PLATFORM { + defaultConfigKeys[v1.TIME_OUT] = true + } + return getConfigKeysMapForPlatformEnt(defaultConfigKeys, platform) +} + +func GetMandatoryConfigKeys(profileName, platformName string) []v1.ConfigKeyStr { + if profileName == v1.GLOBAL_PROFILE_NAME { + return GetConfigKeysMapForPlatform(platformName).GetAllSupportedKeys() } - return string(unit.GetTimeUnitStr()) + return make([]v1.ConfigKeyStr, 0) } -// GetDefaultConfigKeysMap returns a map of default config keys -func GetDefaultConfigKeysMap() map[bean.ConfigKeyStr]bool { - return map[bean.ConfigKeyStr]bool{ - bean.CPU_LIMIT: true, - bean.CPU_REQUEST: true, - bean.MEMORY_LIMIT: true, - bean.MEMORY_REQUEST: true, - bean.TIME_OUT: true, +func GetMissingRequiredConfigKeys(profileName, platformName string, configuredKeys v1.InfraConfigKeys) []v1.ConfigKeyStr { + missingKeys := make([]v1.ConfigKeyStr, 0) + mandatoryKeys := GetMandatoryConfigKeys(profileName, platformName) + for _, missingKey := range configuredKeys.GetUnConfiguredKeys() { + if slices.Contains(mandatoryKeys, missingKey) { + missingKeys = append(missingKeys, missingKey) + } } + return missingKeys +} + +func GetConfigCompositeKey(config *repository.InfraProfileConfigurationEntity) string { + return fmt.Sprintf("%s|%s", GetConfigKeyStr(config.Key), config.UniqueId) } -func GetConfigKeyStr(configKey bean.ConfigKey) bean.ConfigKeyStr { +func GetConfigKeyStr(configKey v1.ConfigKey) v1.ConfigKeyStr { switch configKey { - case bean.CPULimitKey: - return bean.CPU_LIMIT - case bean.CPURequestKey: - return bean.CPU_REQUEST - case bean.MemoryLimitKey: - return bean.MEMORY_LIMIT - case bean.MemoryRequestKey: - return bean.MEMORY_REQUEST - case bean.TimeOutKey: - return bean.TIME_OUT - } - return "" + case v1.CPULimitKey: + return v1.CPU_LIMIT + case v1.CPURequestKey: + return v1.CPU_REQUEST + case v1.MemoryLimitKey: + return v1.MEMORY_LIMIT + case v1.MemoryRequestKey: + return v1.MEMORY_REQUEST + case v1.TimeOutKey: + return v1.TIME_OUT + } + return getEntConfigKeyStr(configKey) } -func GetConfigKey(configKeyStr bean.ConfigKeyStr) bean.ConfigKey { +func GetConfigKey(configKeyStr v1.ConfigKeyStr) v1.ConfigKey { switch configKeyStr { - case bean.CPU_LIMIT: - return bean.CPULimitKey - case bean.CPU_REQUEST: - return bean.CPURequestKey - case bean.MEMORY_LIMIT: - return bean.MemoryLimitKey - case bean.MEMORY_REQUEST: - return bean.MemoryRequestKey - case bean.TIME_OUT: - return bean.TimeOutKey - } - return 0 + case v1.CPU_LIMIT: + return v1.CPULimitKey + case v1.CPU_REQUEST: + return v1.CPURequestKey + case v1.MEMORY_LIMIT: + return v1.MemoryLimitKey + case v1.MEMORY_REQUEST: + return v1.MemoryRequestKey + case v1.TIME_OUT: + return v1.TimeOutKey + } + return getEntConfigKey(configKeyStr) } -// todo remove this validation, as it is written additionally due to validator v9.30.0 constraint for map[string]*struct is not handled -func ValidatePayloadConfig(profileToUpdate *bean.ProfileBeanDto) error { - if len(profileToUpdate.Name) == 0 { - return errors.New("profile name is required") +// ValidatePayloadConfig - validates the payload configuration +func ValidatePayloadConfig(profileToUpdate *v1.ProfileBeanDto) error { + if len(profileToUpdate.GetName()) == 0 { + errMsg := "profile name is required" + return globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) } err := validateProfileAttributes(profileToUpdate.ProfileBeanAbstract) if err != nil { return err } - defaultKeyMap := GetDefaultConfigKeysMap() - for platform, config := range profileToUpdate.Configurations { - err = validatePlatformName(platform, profileToUpdate.BuildxDriverType) + for platform, config := range profileToUpdate.GetConfigurations() { + supportedConfigKeys := GetConfigKeysMapForPlatform(platform) + err = validatePlatformName(platform, profileToUpdate.GetBuildxDriverType()) if err != nil { return err } - err = validateConfigItems(config, defaultKeyMap) + err = validateConfigItems(config, supportedConfigKeys) if err != nil { return err } } return nil } -func validateConfigItems(propertyConfigs []*bean.ConfigurationBean, defaultKeyMap map[bean.ConfigKeyStr]bool) error { + +func validateConfigItems(propertyConfigs []*v1.ConfigurationBean, supportedConfigKeys v1.InfraConfigKeys) error { var validationErrors []string for _, config := range propertyConfigs { - if _, isValidKey := defaultKeyMap[config.Key]; !isValidKey { - validationErrors = append(validationErrors, fmt.Sprintf("invalid configuration property \"%s\"", config.Key)) + if !supportedConfigKeys.IsSupported(config.Key) { + validationErrors = append(validationErrors, fmt.Sprintf("invalid configuration property %q", config.Key)) continue } - //_, err := GetTypedValue(config.Key, config.Value) - //if err != nil { - // validationErrors = append(validationErrors, fmt.Sprintf("error in parsing value for key \"%s\": %v", config.Key, err)) - // continue - //} } // If any validation errors were found, return them as a single error if len(validationErrors) > 0 { - return fmt.Errorf("validation errors: %s", strings.Join(validationErrors, "; ")) - } - return nil -} - -func GetTypedValue(configKey bean.ConfigKeyStr, value interface{}) (interface{}, error) { - switch configKey { - case bean.CPU_LIMIT, bean.CPU_REQUEST, bean.MEMORY_LIMIT, bean.MEMORY_REQUEST: - //value is float64 or convertible to it - switch v := value.(type) { - case string: - valueFloat, err := strconv.ParseFloat(v, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse string to float for %s: %w", configKey, err) - } - return util2.TruncateFloat(valueFloat, 2), nil - case float64: - return util2.TruncateFloat(v, 2), nil - default: - return nil, fmt.Errorf("unsupported type for %s: %v", configKey, reflect.TypeOf(value)) - } - case bean.TIME_OUT: - switch v := value.(type) { - case string: - valueFloat, err := strconv.ParseFloat(v, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse string to float for %s: %w", configKey, err) - } - return math.Min(math.Floor(valueFloat), math.MaxInt64), nil - case float64: - return math.Min(math.Floor(v), math.MaxInt64), nil - default: - return nil, fmt.Errorf("unsupported type for %s: %v", configKey, reflect.TypeOf(value)) - } - // Default case - default: - return nil, fmt.Errorf("unsupported config key: %s", configKey) - } -} - -func IsValidProfileNameRequested(profileName, payloadProfileName string) bool { - if len(payloadProfileName) == 0 || len(profileName) == 0 { - return false - } - if profileName == bean.GLOBAL_PROFILE_NAME && payloadProfileName == bean.GLOBAL_PROFILE_NAME { - return true - } - return false -} - -func IsValidProfileNameRequestedV0(profileName, payloadProfileName string) bool { - if len(payloadProfileName) == 0 || len(profileName) == 0 { - return false - } - if profileName == bean.DEFAULT_PROFILE_NAME && payloadProfileName == bean.DEFAULT_PROFILE_NAME { - return true - } - return false -} - -func validatePlatformName(platform string, buildxDriverType bean.BuildxDriver) error { - if len(platform) == 0 { - return errors.New("platform cannot be empty") - } - if len(platform) > bean.QualifiedPlatformMaxLength { - return errors.New("platform cannot be longer than 50 characters") - } - if !buildxDriverType.IsPlatformSupported(platform) { - return fmt.Errorf("invalid platform name: %q. not supported with driver type: %q", platform, buildxDriverType) + errMsg := fmt.Sprintf("validation errors: %s", strings.Join(validationErrors, "; ")) + return globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) } return nil } -func validateProfileAttributes(profileAbstract bean.ProfileBeanAbstract) error { - if len(profileAbstract.Name) > bean.QualifiedProfileMaxLength { - return errors.New("profile name is too long") - } - if len(profileAbstract.Name) == 0 { - return errors.New("profile name is empty") - } - if len(profileAbstract.Description) > bean.QualifiedDescriptionMaxLength { - return errors.New("profile description is too long") - } - if !profileAbstract.BuildxDriverType.IsValid() { - return fmt.Errorf("invalid buildx driver type: %q", profileAbstract.BuildxDriverType) +func validateProfileAttributes(profileAbstract v1.ProfileBeanAbstract) error { + if len(profileAbstract.GetName()) > v1.QualifiedProfileMaxLength { + errMsg := "profile name is too long" + return globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + if len(profileAbstract.GetName()) == 0 { + errMsg := "profile name is empty" + return globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + if len(profileAbstract.GetDescription()) > v1.QualifiedDescriptionMaxLength { + errMsg := "profile description is too long" + return globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + if !profileAbstract.GetBuildxDriverType().IsValid() { + errMsg := fmt.Sprintf("invalid buildx driver type: %q", profileAbstract.GetBuildxDriverType()) + return globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) } return nil } diff --git a/pkg/infraConfig/util/utils_ent.go b/pkg/infraConfig/util/utils_ent.go new file mode 100644 index 0000000000..edc4c121b9 --- /dev/null +++ b/pkg/infraConfig/util/utils_ent.go @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +import ( + "fmt" + globalUtil "github.com/devtron-labs/devtron/internal/util" + v1 "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "net/http" +) + +func getEntConfigKeyStr(configKey v1.ConfigKey) v1.ConfigKeyStr { + return "" +} + +func getEntConfigKey(configKeyStr v1.ConfigKeyStr) v1.ConfigKey { + return 0 +} + +func getConfigKeysMapForPlatformEnt(defaultConfigKeys v1.InfraConfigKeys, platform string) v1.InfraConfigKeys { + return defaultConfigKeys +} + +func IsValidProfileNameRequested(profileName, payloadProfileName string) bool { + if len(payloadProfileName) == 0 || len(profileName) == 0 { + return false + } + if profileName != v1.GLOBAL_PROFILE_NAME || payloadProfileName != v1.GLOBAL_PROFILE_NAME { + return false + } + return true +} + +func IsValidProfileNameRequestedV0(profileName, payloadProfileName string) bool { + if len(payloadProfileName) == 0 || len(profileName) == 0 { + return false + } + if profileName != v1.GLOBAL_PROFILE_NAME || payloadProfileName != v1.GLOBAL_PROFILE_NAME { + return false + } + return true +} + +func validatePlatformName(platform string, buildxDriverType v1.BuildxDriver) error { + if platform != v1.RUNNER_PLATFORM { + errMsg := fmt.Sprintf("platform %q is not supported", platform) + return globalUtil.NewApiError(http.StatusBadRequest, errMsg, errMsg) + } + return nil +} diff --git a/pkg/infraConfig/wire_infraConfig.go b/pkg/infraConfig/wire_infraConfig.go new file mode 100644 index 0000000000..03e1396a6b --- /dev/null +++ b/pkg/infraConfig/wire_infraConfig.go @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package infraConfig + +import ( + "github.com/devtron-labs/devtron/api/infraConfig" + "github.com/devtron-labs/devtron/pkg/infraConfig/config" + infraRepository "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + auditRepo "github.com/devtron-labs/devtron/pkg/infraConfig/repository/audit" + infraConfigService "github.com/devtron-labs/devtron/pkg/infraConfig/service" + "github.com/devtron-labs/devtron/pkg/infraConfig/service/audit" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/ci" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/job" + "github.com/google/wire" +) + +var WireSet = wire.NewSet( + job.NewJobInfraGetter, + + ci.NewCiInfraGetter, + + infraRepository.NewInfraProfileRepositoryImpl, + wire.Bind(new(infraRepository.InfraConfigRepository), new(*infraRepository.InfraConfigRepositoryImpl)), + + auditRepo.NewInfraConfigAuditRepositoryImpl, + wire.Bind(new(auditRepo.InfraConfigAuditRepository), new(*auditRepo.InfraConfigAuditRepositoryImpl)), + + audit.NewInfraConfigAuditServiceImpl, + wire.Bind(new(audit.InfraConfigAuditService), new(*audit.InfraConfigAuditServiceImpl)), + + config.NewInfraConfigClient, + wire.Bind(new(config.InfraConfigClient), new(*config.InfraConfigClientImpl)), + + infraConfigService.NewInfraConfigServiceImpl, + wire.Bind(new(infraConfigService.InfraConfigService), new(*infraConfigService.InfraConfigServiceImpl)), + + infraProviders.NewInfraProviderImpl, + wire.Bind(new(infraProviders.InfraProvider), new(*infraProviders.InfraProviderImpl)), + + infraConfig.NewInfraConfigRestHandlerImpl, + wire.Bind(new(infraConfig.InfraConfigRestHandler), new(*infraConfig.InfraConfigRestHandlerImpl)), + + infraConfig.NewInfraProfileRouterImpl, + wire.Bind(new(infraConfig.InfraConfigRouter), new(*infraConfig.InfraConfigRouterImpl)), +) diff --git a/pkg/module/ModuleService.go b/pkg/module/ModuleService.go index 3be12527ac..e988bbd583 100644 --- a/pkg/module/ModuleService.go +++ b/pkg/module/ModuleService.go @@ -25,7 +25,7 @@ import ( clientErrors "github.com/devtron-labs/devtron/pkg/errors" moduleRepo "github.com/devtron-labs/devtron/pkg/module/repo" moduleUtil "github.com/devtron-labs/devtron/pkg/module/util" - "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool" "github.com/devtron-labs/devtron/pkg/server" serverBean "github.com/devtron-labs/devtron/pkg/server/bean" serverEnvConfig "github.com/devtron-labs/devtron/pkg/server/config" @@ -61,13 +61,13 @@ type ModuleServiceImpl struct { moduleCronService ModuleCronService moduleServiceHelper ModuleServiceHelper moduleResourceStatusRepository moduleRepo.ModuleResourceStatusRepository - scanToolMetadataService imageScanning.ScanToolMetadataService + scanToolMetadataService scanTool.ScanToolMetadataService } func NewModuleServiceImpl(logger *zap.SugaredLogger, serverEnvConfig *serverEnvConfig.ServerEnvConfig, moduleRepository moduleRepo.ModuleRepository, moduleActionAuditLogRepository ModuleActionAuditLogRepository, helmAppService client.HelmAppService, serverDataStore *serverDataStore.ServerDataStore, serverCacheService server.ServerCacheService, moduleCacheService ModuleCacheService, moduleCronService ModuleCronService, moduleServiceHelper ModuleServiceHelper, moduleResourceStatusRepository moduleRepo.ModuleResourceStatusRepository, - scanToolMetadataService imageScanning.ScanToolMetadataService) *ModuleServiceImpl { + scanToolMetadataService scanTool.ScanToolMetadataService) *ModuleServiceImpl { return &ModuleServiceImpl{ logger: logger, serverEnvConfig: serverEnvConfig, diff --git a/pkg/pipeline/AppArtifactManager.go b/pkg/pipeline/AppArtifactManager.go index 727d734f91..16b1678d49 100644 --- a/pkg/pipeline/AppArtifactManager.go +++ b/pkg/pipeline/AppArtifactManager.go @@ -17,6 +17,7 @@ package pipeline import ( + "github.com/devtron-labs/common-lib/utils" argoApplication "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging" "github.com/devtron-labs/devtron/pkg/build/pipeline" @@ -402,6 +403,7 @@ func (impl *AppArtifactManagerImpl) BuildRollbackArtifactsList(artifactListingFi deployedCiArtifacts = append(deployedCiArtifacts, bean2.CiArtifactBean{ Id: ciArtifact.Id, Image: ciArtifact.Image, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(ciArtifact.TargetPlatforms), MaterialInfo: mInfo, DeployedTime: formatDate(ciArtifact.StartedOn, bean2.LayoutRFC3339), WfrId: ciArtifact.CdWorkflowRunnerId, @@ -656,6 +658,7 @@ func (impl *AppArtifactManagerImpl) BuildArtifactsList(listingFilterOpts *bean.A currentRunningArtifactBean = &bean2.CiArtifactBean{ Id: currentRunningArtifact.Id, Image: currentRunningArtifact.Image, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(currentRunningArtifact.TargetPlatforms), ImageDigest: currentRunningArtifact.ImageDigest, MaterialInfo: mInfo, ScanEnabled: currentRunningArtifact.ScanEnabled, @@ -735,10 +738,11 @@ func (impl *AppArtifactManagerImpl) BuildArtifactsForCdStageV2(listingFilterOpts impl.logger.Errorw("Error in parsing artifact material info", "err", err) } ciArtifact := &bean2.CiArtifactBean{ - Id: artifact.Id, - Image: artifact.Image, - ImageDigest: artifact.ImageDigest, - MaterialInfo: mInfo, + Id: artifact.Id, + Image: artifact.Image, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(artifact.TargetPlatforms), + ImageDigest: artifact.ImageDigest, + MaterialInfo: mInfo, //TODO:LastSuccessfulTriggerOnParent Scanned: artifact.Scanned, ScanEnabled: artifact.ScanEnabled, @@ -781,6 +785,7 @@ func (impl *AppArtifactManagerImpl) BuildArtifactsForCIParentV2(listingFilterOpt ciArtifact := &bean2.CiArtifactBean{ Id: artifact.Id, Image: artifact.Image, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(artifact.TargetPlatforms), ImageDigest: artifact.ImageDigest, MaterialInfo: mInfo, ScanEnabled: artifact.ScanEnabled, diff --git a/pkg/pipeline/AppDeploymentTypeChangeManager.go b/pkg/pipeline/AppDeploymentTypeChangeManager.go index b4312c8e78..a2d4cdcc34 100644 --- a/pkg/pipeline/AppDeploymentTypeChangeManager.go +++ b/pkg/pipeline/AppDeploymentTypeChangeManager.go @@ -19,12 +19,11 @@ package pipeline import ( "context" "fmt" - "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" bean5 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/api/bean/gitOps" "github.com/devtron-labs/devtron/api/helm-app/service" helmBean "github.com/devtron-labs/devtron/api/helm-app/service/bean" - application2 "github.com/devtron-labs/devtron/client/argocdServer/application" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/internal/sql/repository/app" "github.com/devtron-labs/devtron/internal/sql/repository/appStatus" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" @@ -67,19 +66,18 @@ type AppDeploymentTypeChangeManager interface { } type AppDeploymentTypeChangeManagerImpl struct { - logger *zap.SugaredLogger - pipelineRepository pipelineConfig.PipelineRepository - appService app2.AppService - appStatusRepository appStatus.AppStatusRepository - helmAppService service.HelmAppService - application application2.ServiceClient - + logger *zap.SugaredLogger + pipelineRepository pipelineConfig.PipelineRepository + appService app2.AppService + appStatusRepository appStatus.AppStatusRepository + helmAppService service.HelmAppService appArtifactManager AppArtifactManager cdPipelineConfigService CdPipelineConfigService gitOpsConfigReadService config.GitOpsConfigReadService chartService chartService.ChartService workflowEventPublishService out.WorkflowEventPublishService deploymentConfigService common.DeploymentConfigService + ArgoClientWrapperService argocdServer.ArgoClientWrapperService } func NewAppDeploymentTypeChangeManagerImpl( @@ -88,7 +86,6 @@ func NewAppDeploymentTypeChangeManagerImpl( appService app2.AppService, appStatusRepository appStatus.AppStatusRepository, helmAppService service.HelmAppService, - application application2.ServiceClient, appArtifactManager AppArtifactManager, cdPipelineConfigService CdPipelineConfigService, gitOpsConfigReadService config.GitOpsConfigReadService, @@ -101,7 +98,6 @@ func NewAppDeploymentTypeChangeManagerImpl( appService: appService, appStatusRepository: appStatusRepository, helmAppService: helmAppService, - application: application, appArtifactManager: appArtifactManager, cdPipelineConfigService: cdPipelineConfigService, gitOpsConfigReadService: gitOpsConfigReadService, @@ -745,10 +741,7 @@ func (impl *AppDeploymentTypeChangeManagerImpl) fetchDeletedApp(ctx context.Cont } _, err = impl.helmAppService.GetApplicationDetail(ctx, appIdentifier) } else { - req := &application.ApplicationQuery{ - Name: &pipeline.DeploymentAppName, - } - _, err = impl.application.Get(ctx, req) + _, err = impl.ArgoClientWrapperService.GetArgoAppByName(ctx, pipeline.DeploymentAppName) } if err != nil { impl.logger.Errorw("error in getting application detail", "err", err, "deploymentAppName", pipeline.DeploymentAppName) @@ -779,19 +772,10 @@ func (impl *AppDeploymentTypeChangeManagerImpl) fetchDeletedApp(ctx context.Cont // the application in argo cd. func (impl *AppDeploymentTypeChangeManagerImpl) deleteArgoCdApp(ctx context.Context, pipeline *pipelineConfig.Pipeline, deploymentAppName string, cascadeDelete bool) error { - if !pipeline.DeploymentAppCreated { return nil } - - // building the argocd application delete request - req := &application.ApplicationDeleteRequest{ - Name: &deploymentAppName, - Cascade: &cascadeDelete, - } - - _, err := impl.application.Delete(ctx, req) - + _, err := impl.ArgoClientWrapperService.DeleteArgoApp(ctx, deploymentAppName, cascadeDelete) if err != nil { impl.logger.Errorw("error in deleting argocd application", "err", err) // Possible that argocd app got deleted but db updation failed diff --git a/pkg/pipeline/CdHandler.go b/pkg/pipeline/CdHandler.go index 3392f8a308..89d24826e1 100644 --- a/pkg/pipeline/CdHandler.go +++ b/pkg/pipeline/CdHandler.go @@ -20,6 +20,8 @@ import ( "bufio" "errors" "fmt" + "github.com/devtron-labs/common-lib/utils" + bean4 "github.com/devtron-labs/common-lib/utils/bean" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/adapter/cdWorkflow" bean2 "github.com/devtron-labs/devtron/pkg/bean" "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging" @@ -611,6 +613,7 @@ func (impl *CdHandlerImpl) FetchCdWorkflowDetails(appId int, environmentId int, triggeredByUserEmailId = "anonymous" } ciArtifactId := workflow.CiArtifactId + targetPlatforms := []*bean4.TargetPlatform{} if ciArtifactId > 0 { ciArtifact, err := impl.ciArtifactRepository.Get(ciArtifactId) if err != nil { @@ -618,6 +621,8 @@ func (impl *CdHandlerImpl) FetchCdWorkflowDetails(appId int, environmentId int, return types.WorkflowResponse{}, err } + targetPlatforms = utils.ConvertTargetPlatformStringToObject(ciArtifact.TargetPlatforms) + // handling linked ci pipeline if ciArtifact.ParentCiArtifact > 0 && ciArtifact.WorkflowId == nil { ciArtifactId = ciArtifact.ParentCiArtifact @@ -673,6 +678,7 @@ func (impl *CdHandlerImpl) FetchCdWorkflowDetails(appId int, environmentId int, ArtifactId: workflow.CiArtifactId, IsArtifactUploaded: workflow.IsArtifactUploaded, CiPipelineId: ciWf.CiPipelineId, + TargetPlatforms: targetPlatforms, } return workflowResponse, nil @@ -776,6 +782,7 @@ func (impl *CdHandlerImpl) converterWFR(wfr pipelineConfig.CdWorkflowRunner) pip workflow.WorkflowType = string(wfr.WorkflowType) workflow.CdWorkflowId = wfr.CdWorkflowId workflow.Image = wfr.CdWorkflow.CiArtifact.Image + workflow.TargetPlatforms = utils.ConvertTargetPlatformStringToObject(wfr.CdWorkflow.CiArtifact.TargetPlatforms) workflow.PipelineId = wfr.CdWorkflow.PipelineId workflow.CiArtifactId = wfr.CdWorkflow.CiArtifactId isArtifactUploaded, isMigrationRequired := wfr.GetIsArtifactUploaded() diff --git a/pkg/pipeline/CiHandler.go b/pkg/pipeline/CiHandler.go index 49014d3d9f..b6b461f42a 100644 --- a/pkg/pipeline/CiHandler.go +++ b/pkg/pipeline/CiHandler.go @@ -21,6 +21,7 @@ import ( "context" "errors" "fmt" + "github.com/devtron-labs/common-lib/utils" "github.com/devtron-labs/common-lib/utils/workFlow" "github.com/devtron-labs/devtron/internal/sql/constants" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" @@ -571,6 +572,7 @@ func (impl *CiHandlerImpl) GetBuildHistory(pipelineId int, appId int, offset int EnvironmentName: w.EnvironmentName, ReferenceWorkflowId: w.RefCiWorkflowId, PodName: w.PodName, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(w.TargetPlatforms), } if w.Message == bean3.ImageTagUnavailableMessage { @@ -798,6 +800,7 @@ func (impl *CiHandlerImpl) FetchWorkflowDetails(appId int, pipelineId int, build TriggeredBy: workflow.TriggeredBy, TriggeredByEmail: triggeredByUserEmailId, Artifact: ciArtifact.Image, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(ciArtifact.TargetPlatforms), ArtifactId: ciArtifact.Id, IsArtifactUploaded: isArtifactUploaded, EnvironmentId: workflow.EnvironmentId, @@ -1597,6 +1600,7 @@ func (impl *CiHandlerImpl) FetchMaterialInfoByArtifactId(ciArtifactId int, envId Default: deployDetail.Default, ImageTaggingData: *imageTaggingData, Image: ciArtifact.Image, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(ciArtifact.TargetPlatforms), } return gitTriggerInfoResponse, nil } diff --git a/pkg/pipeline/CiService.go b/pkg/pipeline/CiService.go index 9899b84987..1e5d309f19 100644 --- a/pkg/pipeline/CiService.go +++ b/pkg/pipeline/CiService.go @@ -402,7 +402,11 @@ func (impl *CiServiceImpl) TriggerCiPipeline(trigger types.Trigger) (int, error) workflowRequest.CiPipelineType = trigger.PipelineType err = impl.executeCiPipeline(workflowRequest) if err != nil { - impl.Logger.Errorw("workflow error", "err", err) + impl.Logger.Errorw("error in executing ci pipeline", "err", err) + dbErr := impl.markCurrentCiWorkflowFailed(savedCiWf, err) + if dbErr != nil { + impl.Logger.Errorw("update ci workflow error", "err", dbErr) + } return 0, err } impl.Logger.Debugw("ci triggered", " pipeline ", trigger.PipelineId) @@ -820,14 +824,32 @@ func (impl *CiServiceImpl) buildWfRequestForCiPipeline(pipeline *pipelineConfig. ImageScanRetryDelay: impl.config.ImageScanRetryDelay, UseDockerApiToGetDigest: impl.config.UseDockerApiToGetDigest, } - if pipeline.App.AppType == helper.Job { - workflowRequest.AppName = pipeline.App.DisplayName - } + workflowRequest.SetAwsInspectorConfig("") //in oss, there is no pipeline level workflow cache config, so we pass inherit to get the app level config workflowCacheConfig := impl.ciCdPipelineOrchestrator.GetWorkflowCacheConfig(pipeline.App.AppType, trigger.PipelineType, common.WorkflowCacheConfigInherit) workflowRequest.IgnoreDockerCachePush = !workflowCacheConfig.Value workflowRequest.IgnoreDockerCachePull = !workflowCacheConfig.Value impl.Logger.Debugw("Ignore Cache values", "IgnoreDockerCachePush", workflowRequest.IgnoreDockerCachePush, "IgnoreDockerCachePull", workflowRequest.IgnoreDockerCachePull) + if pipeline.App.AppType == helper.Job { + workflowRequest.AppName = pipeline.App.DisplayName + } + if pipeline.ScanEnabled { + scanToolMetadata, scanVia, err := impl.fetchImageScanExecutionMedium() + if err != nil { + impl.Logger.Errorw("error occurred getting scanned via", "err", err) + return nil, err + } + workflowRequest.SetExecuteImageScanningVia(scanVia) + if scanVia.IsScanMediumExternal() { + imageScanExecutionSteps, refPlugins, err := impl.fetchImageScanExecutionStepsForWfRequest(scanToolMetadata) + if err != nil { + impl.Logger.Errorw("error occurred, fetchImageScanExecutionStepsForWfRequest", "scanToolMetadata", scanToolMetadata, "err", err) + return nil, err + } + workflowRequest.SetImageScanningSteps(imageScanExecutionSteps) + workflowRequest.RefPlugins = append(workflowRequest.RefPlugins, refPlugins...) + } + } if dockerRegistry != nil { workflowRequest.DockerRegistryId = dockerRegistry.Id diff --git a/pkg/pipeline/CiService_ent.go b/pkg/pipeline/CiService_ent.go new file mode 100644 index 0000000000..342429d052 --- /dev/null +++ b/pkg/pipeline/CiService_ent.go @@ -0,0 +1,16 @@ +package pipeline + +import ( + "github.com/devtron-labs/common-lib/imageScan/bean" + bean2 "github.com/devtron-labs/devtron/pkg/pipeline/bean" + "github.com/devtron-labs/devtron/pkg/pipeline/types" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/repository" +) + +func (impl *CiServiceImpl) fetchImageScanExecutionMedium() (*repository.ScanToolMetadata, bean.ScanExecutionMedium, error) { + return &repository.ScanToolMetadata{}, "", nil +} + +func (impl *CiServiceImpl) fetchImageScanExecutionStepsForWfRequest(scanToolMetadata *repository.ScanToolMetadata) ([]*types.ImageScanningSteps, []*bean2.RefPluginObject, error) { + return nil, nil, nil +} diff --git a/pkg/pipeline/ConfigMapService.go b/pkg/pipeline/ConfigMapService.go index 8bdae241fe..c7c7b10d9b 100644 --- a/pkg/pipeline/ConfigMapService.go +++ b/pkg/pipeline/ConfigMapService.go @@ -1775,11 +1775,10 @@ func (impl ConfigMapServiceImpl) validateExternalSecretChartCompatibility(appId if configData.ExternalSecret != nil && len(configData.ExternalSecret) > 0 { for _, es := range configData.ExternalSecret { if len(es.Property) > 0 || es.IsBinary == true { - chart, err := impl.commonService.FetchLatestChart(appId, envId) + chartVersion, err := impl.commonService.FetchLatestChartVersion(appId, envId) if err != nil { return false, err } - chartVersion := chart.ChartVersion chartMajorVersion, chartMinorVersion, err := util2.ExtractChartVersion(chartVersion) if err != nil { impl.logger.Errorw("chart version parsing", "err", err) diff --git a/pkg/pipeline/DeploymentPipelineConfigService.go b/pkg/pipeline/DeploymentPipelineConfigService.go index 12b23366b1..904b64d5b7 100644 --- a/pkg/pipeline/DeploymentPipelineConfigService.go +++ b/pkg/pipeline/DeploymentPipelineConfigService.go @@ -21,14 +21,12 @@ import ( "encoding/json" errors3 "errors" "fmt" - application2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" bean2 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/api/bean/gitOps" models2 "github.com/devtron-labs/devtron/api/helm-app/models" client "github.com/devtron-labs/devtron/api/helm-app/service" helmBean "github.com/devtron-labs/devtron/api/helm-app/service/bean" "github.com/devtron-labs/devtron/client/argocdServer" - "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/internal/sql/models" "github.com/devtron-labs/devtron/internal/sql/repository" app2 "github.com/devtron-labs/devtron/internal/sql/repository/app" @@ -150,7 +148,6 @@ type CdPipelineConfigServiceImpl struct { deploymentTemplateHistoryService deploymentTemplate.DeploymentTemplateHistoryService scopedVariableManager variables.ScopedVariableManager deploymentConfig *util2.DeploymentServiceTypeConfig - application application.ServiceClient customTagService CustomTagService ciPipelineConfigService CiPipelineConfigService buildPipelineSwitchService BuildPipelineSwitchService @@ -177,7 +174,7 @@ func NewCdPipelineConfigServiceImpl(logger *zap.SugaredLogger, pipelineRepositor propertiesConfigService PropertiesConfigService, deploymentTemplateHistoryService deploymentTemplate.DeploymentTemplateHistoryService, scopedVariableManager variables.ScopedVariableManager, envVariables *util2.EnvironmentVariables, - application application.ServiceClient, customTagService CustomTagService, + customTagService CustomTagService, ciPipelineConfigService CiPipelineConfigService, buildPipelineSwitchService BuildPipelineSwitchService, argoClientWrapperService argocdServer.ArgoClientWrapperService, deployedAppMetricsService deployedAppMetrics.DeployedAppMetricsService, @@ -212,7 +209,6 @@ func NewCdPipelineConfigServiceImpl(logger *zap.SugaredLogger, pipelineRepositor deploymentTemplateHistoryService: deploymentTemplateHistoryService, scopedVariableManager: scopedVariableManager, deploymentConfig: envVariables.DeploymentServiceTypeConfig, - application: application, chartService: chartService, customTagService: customTagService, ciPipelineConfigService: ciPipelineConfigService, @@ -404,10 +400,12 @@ func (impl *CdPipelineConfigServiceImpl) CreateCdPipelines(pipelineCreateRequest pipeline.DeploymentAppType = overrideDeploymentType } - err = impl.checkIfNsExistsForEnvIds(envIds) - if err != nil { - impl.logger.Errorw("error in checking existence of namespace for env's", "envIds", envIds, "err", err) - return nil, err + if impl.deploymentConfig.ShouldCheckNamespaceOnClone { + err = impl.checkIfNsExistsForEnvIds(envIds) + if err != nil { + impl.logger.Errorw("error in checking existence of namespace for env's", "envIds", envIds, "err", err) + return nil, err + } } isGitOpsRequiredForCD := impl.IsGitOpsRequiredForCD(pipelineCreateRequest) @@ -875,11 +873,7 @@ func (impl *CdPipelineConfigServiceImpl) DeleteCdPipeline(pipeline *pipelineConf } impl.logger.Debugw("acd app is already deleted for this pipeline", "pipeline", pipeline) if deleteFromAcd { - req := &application2.ApplicationDeleteRequest{ - Name: &deploymentAppName, - Cascade: &cascadeDelete, - } - if _, err := impl.application.Delete(ctx, req); err != nil { + if _, err := impl.argoClientWrapperService.DeleteArgoApp(ctx, deploymentAppName, cascadeDelete); err != nil { impl.logger.Errorw("err in deleting pipeline on argocd", "id", pipeline, "err", err) if forceDelete { @@ -961,12 +955,7 @@ func (impl *CdPipelineConfigServiceImpl) DeleteACDAppCdPipelineWithNonCascade(pi if pipeline.DeploymentAppCreated && util.IsAcdApp(envDeploymentConfig.DeploymentAppType) { deploymentAppName := pipeline.DeploymentAppName impl.logger.Debugw("acd app is already deleted for this pipeline", "pipeline", pipeline) - cascadeDelete := false - req := &application2.ApplicationDeleteRequest{ - Name: &deploymentAppName, - Cascade: &cascadeDelete, - } - if _, err = impl.application.Delete(ctx, req); err != nil { + if _, err = impl.argoClientWrapperService.DeleteArgoApp(ctx, deploymentAppName, false); err != nil { impl.logger.Errorw("err in deleting pipeline on argocd", "id", pipeline, "err", err) //statusError, _ := err.(*errors2.StatusError) if !strings.Contains(err.Error(), "code = NotFound") { @@ -1501,7 +1490,7 @@ func (impl *CdPipelineConfigServiceImpl) MarkGitOpsDevtronAppsDeletedWhereArgoAp acdAppFound := false acdAppName := pipeline.DeploymentAppName - _, err := impl.application.Get(context.Background(), &application2.ApplicationQuery{Name: &acdAppName}) + _, err := impl.argoClientWrapperService.GetArgoAppByName(context.Background(), acdAppName) if err == nil { // acd app is not yet deleted so return acdAppFound = true @@ -2068,11 +2057,7 @@ func (impl *CdPipelineConfigServiceImpl) DeleteCdPipelinePartial(pipeline *pipel } } impl.logger.Debugw("acd app is already deleted for this pipeline", "pipeline", pipeline) - req := &application2.ApplicationDeleteRequest{ - Name: &deploymentAppName, - Cascade: &cascadeDelete, - } - if _, err := impl.application.Delete(ctx, req); err != nil { + if _, err := impl.argoClientWrapperService.DeleteArgoApp(ctx, deploymentAppName, cascadeDelete); err != nil { impl.logger.Errorw("err in deleting pipeline on argocd", "id", pipeline, "err", err) if forceDelete { diff --git a/pkg/pipeline/DockerRegistryConfig.go b/pkg/pipeline/DockerRegistryConfig.go index 3111cf98e8..63c13e30ff 100644 --- a/pkg/pipeline/DockerRegistryConfig.go +++ b/pkg/pipeline/DockerRegistryConfig.go @@ -21,7 +21,7 @@ import ( "fmt" bean2 "github.com/devtron-labs/devtron/api/helm-app/gRPC" client "github.com/devtron-labs/devtron/api/helm-app/service" - "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient" + "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/pkg/pipeline/types" "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" @@ -65,19 +65,20 @@ type DockerRegistryConfigImpl struct { dockerArtifactStoreRepository repository.DockerArtifactStoreRepository dockerRegistryIpsConfigRepository repository.DockerRegistryIpsConfigRepository ociRegistryConfigRepository repository.OCIRegistryConfigRepository - RepositorySecret repoCredsK8sClient.RepositoryCreds + argoClientWrapperService argocdServer.ArgoClientWrapperService } func NewDockerRegistryConfigImpl(logger *zap.SugaredLogger, helmAppService client.HelmAppService, dockerArtifactStoreRepository repository.DockerArtifactStoreRepository, dockerRegistryIpsConfigRepository repository.DockerRegistryIpsConfigRepository, ociRegistryConfigRepository repository.OCIRegistryConfigRepository, - RepositorySecret repoCredsK8sClient.RepositoryCreds) *DockerRegistryConfigImpl { + argoClientWrapperService argocdServer.ArgoClientWrapperService, +) *DockerRegistryConfigImpl { return &DockerRegistryConfigImpl{ logger: logger, helmAppService: helmAppService, dockerArtifactStoreRepository: dockerArtifactStoreRepository, dockerRegistryIpsConfigRepository: dockerRegistryIpsConfigRepository, ociRegistryConfigRepository: ociRegistryConfigRepository, - RepositorySecret: RepositorySecret, + argoClientWrapperService: argoClientWrapperService, } } @@ -298,7 +299,7 @@ func (impl DockerRegistryConfigImpl) ConfigureOCIRegistry(bean *types.DockerArti func (impl DockerRegistryConfigImpl) CreateArgoRepositorySecretForRepositories(artifactStore *types.DockerArtifactStoreBean, ociRegistryConfig *repository.OCIRegistryConfig) error { for _, repo := range artifactStore.RepositoryList { - err := impl.RepositorySecret.AddOrUpdateOCIRegistry(artifactStore.Username, + err := impl.argoClientWrapperService.AddOrUpdateOCIRegistry(artifactStore.Username, artifactStore.Password, ociRegistryConfig.Id, artifactStore.RegistryURL, @@ -855,7 +856,7 @@ func (impl DockerRegistryConfigImpl) DeleteReg(bean *types.DockerArtifactStoreBe if ociRegistryConfig.RepositoryType == repository.OCI_REGISRTY_REPO_TYPE_CHART { repositoryList := strings.Split(ociRegistryConfig.RepositoryList, ",") for _, repo := range repositoryList { - err = impl.RepositorySecret.DeleteOCIRegistry(dockerReg.RegistryURL, repo, ociRegistryConfig.Id) + err = impl.argoClientWrapperService.DeleteOCIRegistry(dockerReg.RegistryURL, repo, ociRegistryConfig.Id) if err != nil { impl.logger.Errorw("error in deleting OCI registry secret", "err", err) //intentionally ignoring error diff --git a/pkg/pipeline/WorkflowService.go b/pkg/pipeline/WorkflowService.go index c69c377d02..3cc2215867 100644 --- a/pkg/pipeline/WorkflowService.go +++ b/pkg/pipeline/WorkflowService.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "errors" + "fmt" v1alpha12 "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned/typed/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/workflow/util" "github.com/devtron-labs/common-lib/utils" @@ -27,14 +28,15 @@ import ( "github.com/devtron-labs/common-lib/utils/k8s/commonBean" "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" - "github.com/devtron-labs/devtron/pkg/app" bean2 "github.com/devtron-labs/devtron/pkg/build/pipeline/bean" repository2 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" - bean4 "github.com/devtron-labs/devtron/pkg/infraConfig/bean" + "github.com/devtron-labs/devtron/pkg/config/read" + v1 "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" k8s2 "github.com/devtron-labs/devtron/pkg/k8s" bean3 "github.com/devtron-labs/devtron/pkg/pipeline/bean" "github.com/devtron-labs/devtron/pkg/pipeline/executors" "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters" "github.com/devtron-labs/devtron/pkg/pipeline/types" "go.uber.org/zap" v12 "k8s.io/api/core/v1" @@ -62,7 +64,7 @@ type WorkflowServiceImpl struct { Logger *zap.SugaredLogger config *rest.Config ciCdConfig *types.CiCdConfig - appService app.AppService + configMapService read.ConfigReadService envRepository repository2.EnvironmentRepository globalCMCSService GlobalCMCSService argoWorkflowExecutor executors.ArgoWorkflowExecutor @@ -74,15 +76,20 @@ type WorkflowServiceImpl struct { // TODO: Move to bean -func NewWorkflowServiceImpl(Logger *zap.SugaredLogger, envRepository repository2.EnvironmentRepository, ciCdConfig *types.CiCdConfig, - appService app.AppService, globalCMCSService GlobalCMCSService, argoWorkflowExecutor executors.ArgoWorkflowExecutor, +func NewWorkflowServiceImpl(Logger *zap.SugaredLogger, + envRepository repository2.EnvironmentRepository, + ciCdConfig *types.CiCdConfig, + configMapService read.ConfigReadService, + globalCMCSService GlobalCMCSService, + argoWorkflowExecutor executors.ArgoWorkflowExecutor, k8sUtil *k8s.K8sServiceImpl, - systemWorkflowExecutor executors.SystemWorkflowExecutor, k8sCommonService k8s2.K8sCommonService, + systemWorkflowExecutor executors.SystemWorkflowExecutor, + k8sCommonService k8s2.K8sCommonService, infraProvider infraProviders.InfraProvider) (*WorkflowServiceImpl, error) { commonWorkflowService := &WorkflowServiceImpl{ Logger: Logger, ciCdConfig: ciCdConfig, - appService: appService, + configMapService: configMapService, envRepository: envRepository, globalCMCSService: globalCMCSService, argoWorkflowExecutor: argoWorkflowExecutor, @@ -134,37 +141,62 @@ func (impl *WorkflowServiceImpl) createWorkflowTemplate(workflowRequest *types.W return bean3.WorkflowTemplate{}, err } - shouldAddExistingCmCsInWorkflow := impl.shouldAddExistingCmCsInWorkflow(workflowRequest) - if shouldAddExistingCmCsInWorkflow { - workflowConfigMaps, workflowSecrets, err = impl.addExistingCmCsInWorkflow(workflowRequest, workflowConfigMaps, workflowSecrets) - if err != nil { - impl.Logger.Errorw("error occurred while adding existing CmCs", "err", err) - return bean3.WorkflowTemplate{}, err - } - } - - workflowTemplate.ConfigMaps = workflowConfigMaps - workflowTemplate.Secrets = workflowSecrets - workflowTemplate.Volumes = executors.ExtractVolumesFromCmCs(workflowConfigMaps, workflowSecrets) - workflowRequest.AddNodeConstraintsFromConfig(&workflowTemplate, impl.ciCdConfig) - infraConfiguration := &bean4.InfraConfig{} + infraConfiguration := &v1.InfraConfig{} + shouldAddExistingCmCsInWorkflow := impl.shouldAddExistingCmCsInWorkflow(workflowRequest) if workflowRequest.Type == bean3.CI_WORKFLOW_PIPELINE_TYPE || workflowRequest.Type == bean3.JOB_WORKFLOW_PIPELINE_TYPE { nodeSelector := impl.getAppLabelNodeSelector(workflowRequest) if nodeSelector != nil { workflowTemplate.NodeSelector = nodeSelector } - infraConfigScope := &bean4.Scope{ - AppId: workflowRequest.AppId, - } + infraGetterRequest := infraGetters.NewInfraRequest(workflowRequest.Scope). + WithAppId(workflowRequest.AppId). + WithEnvId(workflowRequest.EnvironmentId). + WithPlatform(v1.RUNNER_PLATFORM) infraGetter, _ := impl.infraProvider.GetInfraProvider(workflowRequest.Type) - infraConfiguration, err = infraGetter.GetInfraConfigurationsByScopeAndPlatform(infraConfigScope, bean4.RUNNER_PLATFORM) + infraConfigurations, err := infraGetter.GetConfigurationsByScopeAndTargetPlatforms(infraGetterRequest) + if err != nil { + impl.Logger.Errorw("error occurred while getting infra config", "infraGetterRequest", infraGetterRequest, "err", err) + return bean3.WorkflowTemplate{}, err + } + impl.Logger.Debugw("infra config for workflow", "infraConfigurations", infraConfigurations, "infraGetterRequest", infraGetterRequest) + infraConfiguration = infraConfigurations[v1.RUNNER_PLATFORM] + infraConfigMaps, infraSecrets, err := impl.prepareCmCsForWorkflowTemplate(workflowRequest, infraConfiguration.ConfigMaps, infraConfiguration.Secrets) if err != nil { - impl.Logger.Errorw("error occurred while getting infra config", "infraConfigScope", infraConfigScope, "err", err) + impl.Logger.Errorw("error occurred while preparing build infra cm/ cs for workflow template", "err", err) return bean3.WorkflowTemplate{}, err } - workflowTemplate.SetActiveDeadlineSeconds(infraConfiguration.GetCiDefaultTimeout()) + workflowConfigMaps = append(workflowConfigMaps, infraConfigMaps...) + workflowSecrets = append(workflowSecrets, infraSecrets...) + workflowRequest.AddInfraConfigurations(&workflowTemplate, infraConfiguration) + err = infraGetter.SaveInfraConfigHistorySnapshot(workflowRequest.WorkflowId, workflowRequest.TriggeredBy, infraConfigurations) + if err != nil { + impl.Logger.Errorw("error occurred while saving infra config history snapshot", "err", err, "infraConfigurations", infraConfigurations, "workflowId", workflowRequest.WorkflowId) + } + } else { + if shouldAddExistingCmCsInWorkflow { + cdStageConfigMaps, cdStageSecrets, err := impl.addExistingCmCsInWorkflowForCDStage(workflowRequest) + if err != nil { + impl.Logger.Errorw("error occurred while adding existing cm/ cs", "err", err) + return bean3.WorkflowTemplate{}, err + } + cdStageModifiedConfigMaps, cdStageModifiedSecrets, err := impl.prepareCmCsForWorkflowTemplate(workflowRequest, cdStageConfigMaps, cdStageSecrets) + if err != nil { + impl.Logger.Errorw("error occurred while preparing cd stage cm/ cs for workflow template", "err", err) + return bean3.WorkflowTemplate{}, err + } + workflowConfigMaps = append(workflowConfigMaps, cdStageModifiedConfigMaps...) + workflowSecrets = append(workflowSecrets, cdStageModifiedSecrets...) + } } + // internally inducing BlobStorageCmName and BlobStorageSecretName for getting logs, caches and artifacts from + // in-cluster configured blob storage, if USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW = false and isExt = true + if shouldAddExistingCmCsInWorkflow && workflowRequest.UseExternalClusterBlob { + workflowConfigMaps, workflowSecrets = impl.addExtBlobStorageCmCsInResponse(workflowConfigMaps, workflowSecrets) + } + workflowTemplate.ConfigMaps = workflowConfigMaps + workflowTemplate.Secrets = workflowSecrets + workflowTemplate.Volumes = executors.ExtractVolumes(workflowConfigMaps, workflowSecrets) workflowMainContainer, err := workflowRequest.GetWorkflowMainContainer(impl.ciCdConfig, infraConfiguration, workflowJson, &workflowTemplate, workflowConfigMaps, workflowSecrets) if err != nil { @@ -241,50 +273,62 @@ func (impl *WorkflowServiceImpl) appendGlobalCMCS(workflowRequest *types.Workflo return workflowConfigMaps, workflowSecrets, nil } -func (impl *WorkflowServiceImpl) addExistingCmCsInWorkflow(workflowRequest *types.WorkflowRequest, workflowConfigMaps []bean.ConfigSecretMap, workflowSecrets []bean.ConfigSecretMap) ([]bean.ConfigSecretMap, []bean.ConfigSecretMap, error) { +func (impl *WorkflowServiceImpl) addExistingCmCsInWorkflowForCDStage(workflowRequest *types.WorkflowRequest) ([]bean.ConfigSecretMap, []bean.ConfigSecretMap, error) { + workflowConfigMaps := make([]bean.ConfigSecretMap, 0) + workflowSecrets := make([]bean.ConfigSecretMap, 0) + existingConfigMap, existingSecrets, err := impl.configMapService.GetCmCsForPrePostStageTrigger(workflowRequest.Scope, workflowRequest.AppId, workflowRequest.EnvironmentId, false) + if err != nil { + impl.Logger.Errorw("failed to get configmap data", "err", err) + return nil, nil, err + } + impl.Logger.Debugw("existing cm", "cm", existingConfigMap, "secrets", existingSecrets) + if existingConfigMap != nil { + for i := range existingConfigMap.Maps { + workflowConfigMaps = append(workflowConfigMaps, existingConfigMap.Maps[i]) + } + } + if existingSecrets != nil { + for i := range existingSecrets.Secrets { + if existingSecrets.Secrets[i] == nil { + continue + } + workflowSecrets = append(workflowSecrets, *existingSecrets.Secrets[i]) + } + } + return workflowConfigMaps, workflowSecrets, nil +} +func (impl *WorkflowServiceImpl) prepareCmCsForWorkflowTemplate(workflowRequest *types.WorkflowRequest, workflowConfigMaps []bean.ConfigSecretMap, workflowSecrets []bean.ConfigSecretMap) ([]bean.ConfigSecretMap, []bean.ConfigSecretMap, error) { + modifiedWorkflowConfigMaps := make([]bean.ConfigSecretMap, 0) + modifiedWorkflowSecrets := make([]bean.ConfigSecretMap, 0) pipelineLevelConfigMaps, pipelineLevelSecrets, err := workflowRequest.GetConfiguredCmCs() if err != nil { impl.Logger.Errorw("error occurred while fetching pipeline configured cm and cs", "pipelineId", workflowRequest.Pipeline.Id, "err", err) return nil, nil, err } - isJob := workflowRequest.CheckForJob() - allowAll := isJob + allowAll := workflowRequest.IsDevtronJob() || workflowRequest.IsDevtronCI() namePrefix := workflowRequest.GetExistingCmCsNamePrefix() - existingConfigMap, existingSecrets, err := impl.appService.GetCmSecretNew(workflowRequest.AppId, workflowRequest.EnvironmentId, isJob, workflowRequest.Scope) - if err != nil { - impl.Logger.Errorw("failed to get configmap data", "err", err) - return nil, nil, err - } - impl.Logger.Debugw("existing cm", "cm", existingConfigMap, "secrets", existingSecrets) - - for _, cm := range existingConfigMap.Maps { - // HERE we are allowing all existingSecrets in case of JOB + for _, cm := range workflowConfigMaps { + // HERE we are allowing all existingSecrets in case of JOB/ BUILD Infra if _, ok := pipelineLevelConfigMaps[cm.Name]; ok || allowAll { if !cm.External { - cm.Name = cm.Name + "-" + namePrefix + cm.Name = fmt.Sprintf("%s-cm-%s", cm.Name, namePrefix) } - workflowConfigMaps = append(workflowConfigMaps, cm) + modifiedWorkflowConfigMaps = append(modifiedWorkflowConfigMaps, cm) } } - for _, secret := range existingSecrets.Secrets { - // HERE we are allowing all existingSecrets in case of JOB + for _, secret := range workflowSecrets { + // HERE we are allowing all existingSecrets in case of JOB/ BUILD Infra if _, ok := pipelineLevelSecrets[secret.Name]; ok || allowAll { if !secret.External { - secret.Name = secret.Name + "-" + namePrefix + secret.Name = fmt.Sprintf("%s-cs-%s", secret.Name, namePrefix) } - workflowSecrets = append(workflowSecrets, *secret) + modifiedWorkflowSecrets = append(modifiedWorkflowSecrets, secret) } } - - // internally inducing BlobStorageCmName and BlobStorageSecretName for getting logs, caches and artifacts from - // in-cluster configured blob storage, if USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW = false and isExt = true - if workflowRequest.UseExternalClusterBlob { - workflowConfigMaps, workflowSecrets = impl.addExtBlobStorageCmCsInResponse(workflowConfigMaps, workflowSecrets) - } - - return workflowConfigMaps, workflowSecrets, nil + return modifiedWorkflowConfigMaps, modifiedWorkflowSecrets, nil } + func (impl *WorkflowServiceImpl) addExtBlobStorageCmCsInResponse(workflowConfigMaps []bean.ConfigSecretMap, workflowSecrets []bean.ConfigSecretMap) ([]bean.ConfigSecretMap, []bean.ConfigSecretMap) { blobDetailsConfigMap := bean.ConfigSecretMap{ Name: impl.ciCdConfig.ExtBlobStorageCmName, @@ -312,7 +356,7 @@ func (impl *WorkflowServiceImpl) updateBlobStorageConfig(workflowRequest *types. func (impl *WorkflowServiceImpl) getAppLabelNodeSelector(workflowRequest *types.WorkflowRequest) map[string]string { // node selector - if val, ok := workflowRequest.AppLabels[CI_NODE_SELECTOR_APP_LABEL_KEY]; ok && !(workflowRequest.CheckForJob() && workflowRequest.IsExtRun) { + if val, ok := workflowRequest.AppLabels[CI_NODE_SELECTOR_APP_LABEL_KEY]; ok && !(workflowRequest.IsDevtronJob() && workflowRequest.IsExtRun) { var nodeSelectors map[string]string // Unmarshal or Decode the JSON to the interface. err := json.Unmarshal([]byte(val), &nodeSelectors) diff --git a/pkg/pipeline/adapter/adapter.go b/pkg/pipeline/adapter/adapter.go index f709c84c20..427d97d1b4 100644 --- a/pkg/pipeline/adapter/adapter.go +++ b/pkg/pipeline/adapter/adapter.go @@ -377,4 +377,4 @@ func GetStepVariableDto(variable *repository.PipelineStageStepVariable) (*pipeli VariableStepIndexInPlugin: variable.VariableStepIndexInPlugin, } return variableDto, nil -} \ No newline at end of file +} diff --git a/pkg/pipeline/bean/CdHandlerBean.go b/pkg/pipeline/bean/CdHandlerBean.go index d255c478d8..a3118943d6 100644 --- a/pkg/pipeline/bean/CdHandlerBean.go +++ b/pkg/pipeline/bean/CdHandlerBean.go @@ -1,6 +1,7 @@ package bean import ( + "github.com/devtron-labs/common-lib/utils/bean" "github.com/devtron-labs/devtron/internal/sql/repository/imageTagging" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "time" @@ -21,6 +22,7 @@ type CdWorkflowWithArtifact struct { TriggeredBy int32 `json:"triggered_by"` EmailId string `json:"email_id"` Image string `json:"image"` + TargetPlatforms []*bean.TargetPlatform `json:"targetPlatforms"` MaterialInfo string `json:"material_info,omitempty"` DataSource string `json:"data_source,omitempty"` CiArtifactId int `json:"ci_artifact_id,omitempty"` diff --git a/pkg/pipeline/bean/ConfigMapBean.go b/pkg/pipeline/bean/ConfigMapBean.go index 92bf41a970..f61dfe463a 100644 --- a/pkg/pipeline/bean/ConfigMapBean.go +++ b/pkg/pipeline/bean/ConfigMapBean.go @@ -19,6 +19,7 @@ package bean import ( "encoding/json" "github.com/devtron-labs/devtron/internal/sql/models" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" "strings" ) @@ -145,3 +146,31 @@ const ( func (r ResourceType) ToString() string { return string(r) } + +type ResolvedCmCsRequest struct { + Scope resourceQualifiers.Scope + AppId int + EnvId int + IsJob bool +} + +func NewResolvedCmCsRequest(scope resourceQualifiers.Scope) *ResolvedCmCsRequest { + return &ResolvedCmCsRequest{ + Scope: scope, + } +} + +func (r *ResolvedCmCsRequest) WithAppId(appId int) *ResolvedCmCsRequest { + r.AppId = appId + return r +} + +func (r *ResolvedCmCsRequest) WithEnvId(envId int) *ResolvedCmCsRequest { + r.EnvId = envId + return r +} + +func (r *ResolvedCmCsRequest) ForJob(isJob bool) *ResolvedCmCsRequest { + r.IsJob = isJob + return r +} diff --git a/pkg/pipeline/executors/WorkflowUtils.go b/pkg/pipeline/executors/WorkflowUtils.go index 2933356f29..ed2aae3e98 100644 --- a/pkg/pipeline/executors/WorkflowUtils.go +++ b/pkg/pipeline/executors/WorkflowUtils.go @@ -21,6 +21,7 @@ import ( "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned" v1alpha12 "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned/typed/workflow/v1alpha1" + "github.com/devtron-labs/common-lib/utils" bean2 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/pkg/pipeline/bean" @@ -34,6 +35,17 @@ import ( var ArgoWorkflowOwnerRef = v1.OwnerReference{APIVersion: "argoproj.io/v1alpha1", Kind: "Workflow", Name: "{{workflow.name}}", UID: "{{workflow.uid}}", BlockOwnerDeletion: &[]bool{true}[0]} +func ExtractVolumes(configMaps []bean2.ConfigSecretMap, secrets []bean2.ConfigSecretMap) []v12.Volume { + var volumes []v12.Volume + configMapVolumes := ExtractVolumesFromCmCs(configMaps, secrets) + volumes = append(volumes, configMapVolumes...) + + // Add downwardAPI volume + downwardAPIVolume := createDownwardAPIVolume() + volumes = append(volumes, downwardAPIVolume) + return volumes +} + func ExtractVolumesFromCmCs(configMaps []bean2.ConfigSecretMap, secrets []bean2.ConfigSecretMap) []v12.Volume { var volumes []v12.Volume configMapVolumes := extractVolumesFromConfigSecretMaps(true, configMaps) @@ -45,9 +57,34 @@ func ExtractVolumesFromCmCs(configMaps []bean2.ConfigSecretMap, secrets []bean2. for _, volume := range secretVolumes { volumes = append(volumes, volume) } + return volumes } +func createDownwardAPIVolume() v12.Volume { + return v12.Volume{ + Name: utils.DEVTRON_SELF_DOWNWARD_API_VOLUME, + VolumeSource: v12.VolumeSource{ + DownwardAPI: &v12.DownwardAPIVolumeSource{ + Items: []v12.DownwardAPIVolumeFile{ + { + Path: utils.POD_LABELS, + FieldRef: &v12.ObjectFieldSelector{ + FieldPath: "metadata." + utils.POD_LABELS, + }, + }, + { + Path: utils.POD_ANNOTATIONS, + FieldRef: &v12.ObjectFieldSelector{ + FieldPath: "metadata." + utils.POD_ANNOTATIONS, + }, + }, + }, + }, + }, + } +} + func extractVolumesFromConfigSecretMaps(isCm bool, configSecretMaps []bean2.ConfigSecretMap) []v12.Volume { var volumes []v12.Volume for _, configSecretMap := range configSecretMaps { diff --git a/pkg/pipeline/infraProviders/InfraProvider.go b/pkg/pipeline/infraProviders/InfraProvider.go index 721ee11d4f..eb11d6f63b 100644 --- a/pkg/pipeline/infraProviders/InfraProvider.go +++ b/pkg/pipeline/infraProviders/InfraProvider.go @@ -17,10 +17,9 @@ package infraProviders import ( - "github.com/devtron-labs/devtron/pkg/infraConfig/service" "github.com/devtron-labs/devtron/pkg/pipeline/bean" "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters" - "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/ciPipeline" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/ci" "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/job" "github.com/pkg/errors" "go.uber.org/zap" @@ -36,11 +35,13 @@ type InfraProviderImpl struct { jobInfraGetter infraGetters.InfraGetter } -func NewInfraProviderImpl(logger *zap.SugaredLogger, service service.InfraConfigService) *InfraProviderImpl { +func NewInfraProviderImpl(logger *zap.SugaredLogger, + jobInfraGetter *job.InfraGetter, + ciInfraGetter *ci.InfraGetter) *InfraProviderImpl { return &InfraProviderImpl{ logger: logger, - ciInfraGetter: ciPipeline.NewCiInfraGetter(service), - jobInfraGetter: job.NewJobInfraGetter(), + ciInfraGetter: ciInfraGetter, + jobInfraGetter: jobInfraGetter, } } diff --git a/pkg/pipeline/infraProviders/infraGetters/ci/ciPipelineInfraGetter.go b/pkg/pipeline/infraProviders/infraGetters/ci/ciPipelineInfraGetter.go new file mode 100644 index 0000000000..b7ea98e65d --- /dev/null +++ b/pkg/pipeline/infraProviders/infraGetters/ci/ciPipelineInfraGetter.go @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ci + +import ( + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/service" + "github.com/devtron-labs/devtron/pkg/infraConfig/service/audit" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters" + "go.uber.org/zap" +) + +// InfraGetter gets infra config for ci workflows +type InfraGetter struct { + logger *zap.SugaredLogger + infraConfigService service.InfraConfigService + infraConfigAuditService audit.InfraConfigAuditService +} + +func NewCiInfraGetter(logger *zap.SugaredLogger, + infraConfigService service.InfraConfigService, + infraConfigAuditService audit.InfraConfigAuditService) *InfraGetter { + return &InfraGetter{ + logger: logger, + infraConfigService: infraConfigService, + infraConfigAuditService: infraConfigAuditService, + } +} + +// GetConfigurationsByScopeAndTargetPlatforms gets infra config for ci workflows using the scope +func (ciInfraGetter *InfraGetter) GetConfigurationsByScopeAndTargetPlatforms(request *infraGetters.InfraRequest) (map[string]*v1.InfraConfig, error) { + return ciInfraGetter.infraConfigService.GetConfigurationsByScopeAndTargetPlatforms(request.GetWorkflowScope(), request.GetTargetPlatforms()) +} + +func (ciInfraGetter *InfraGetter) SaveInfraConfigHistorySnapshot(workflowId int, triggeredBy int32, infraConfigs map[string]*v1.InfraConfig) error { + tx, err := ciInfraGetter.infraConfigAuditService.StartTx() + if err != nil { + ciInfraGetter.logger.Errorw("error in starting the transaction", "err", err) + return err + } + defer ciInfraGetter.infraConfigAuditService.RollbackTx(tx) + err = ciInfraGetter.infraConfigAuditService.SaveCiInfraConfigHistorySnapshot(tx, workflowId, triggeredBy, infraConfigs) + if err != nil { + ciInfraGetter.logger.Errorw("error in creating ci infra trigger snapshot", "infraConfigs", infraConfigs, "err", err) + return err + } + err = ciInfraGetter.infraConfigService.HandleInfraConfigTriggerAudit(workflowId, triggeredBy, infraConfigs) + if err != nil { + ciInfraGetter.logger.Errorw("error in handling infra config trigger audit", "infraConfigs", infraConfigs, "err", err) + return err + } + err = tx.Commit() + if err != nil { + ciInfraGetter.logger.Errorw("err in committing transaction", "err", err) + return err + } + return nil +} diff --git a/pkg/pipeline/infraProviders/infraGetters/ciPipeline/ciPipelineInfraGetter.go b/pkg/pipeline/infraProviders/infraGetters/ciPipeline/ciPipelineInfraGetter.go deleted file mode 100644 index 09c2b5024e..0000000000 --- a/pkg/pipeline/infraProviders/infraGetters/ciPipeline/ciPipelineInfraGetter.go +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ciPipeline - -import ( - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" - "github.com/devtron-labs/devtron/pkg/infraConfig/service" -) - -// CiInfraGetter gets infra config for ci workflows -type CiInfraGetter struct { - infraConfigService service.InfraConfigService -} - -func NewCiInfraGetter(infraConfigService service.InfraConfigService) *CiInfraGetter { - return &CiInfraGetter{infraConfigService: infraConfigService} -} - -// GetInfraConfigurationsByScope gets infra config for ci workflows using the scope -func (ciInfraGetter CiInfraGetter) GetInfraConfigurationsByScopeAndPlatform(scope *bean.Scope, platform string) (*bean.InfraConfig, error) { - return ciInfraGetter.infraConfigService.GetInfraConfigurationsByScopeAndPlatform(scope, platform) -} diff --git a/pkg/pipeline/infraProviders/infraGetters/infraGetter.go b/pkg/pipeline/infraProviders/infraGetters/infraGetter.go index d8a7d632a7..a69141845e 100644 --- a/pkg/pipeline/infraProviders/infraGetters/infraGetter.go +++ b/pkg/pipeline/infraProviders/infraGetters/infraGetter.go @@ -17,9 +17,73 @@ package infraGetters import ( - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" ) type InfraGetter interface { - GetInfraConfigurationsByScopeAndPlatform(scope *bean.Scope, platform string) (*bean.InfraConfig, error) + GetConfigurationsByScopeAndTargetPlatforms(request *InfraRequest) (map[string]*v1.InfraConfig, error) + SaveInfraConfigHistorySnapshot(workflowId int, triggeredBy int32, infraConfigs map[string]*v1.InfraConfig) error +} + +type InfraRequest struct { + scope resourceQualifiers.Scope + appId int + envId int + targetPlatforms []string +} + +func NewInfraRequest(scope resourceQualifiers.Scope) *InfraRequest { + return &InfraRequest{ + scope: scope, + } +} + +func (infraRequest *InfraRequest) WithAppId(appId int) *InfraRequest { + infraRequest.appId = appId + return infraRequest +} + +func (infraRequest *InfraRequest) WithEnvId(envId int) *InfraRequest { + infraRequest.envId = envId + return infraRequest +} + +func (infraRequest *InfraRequest) WithPlatform(platforms ...string) *InfraRequest { + for _, platform := range platforms { + if platform == "" { + platform = v1.RUNNER_PLATFORM + } else { + infraRequest.targetPlatforms = append(infraRequest.targetPlatforms, platform) + } + } + return infraRequest +} + +func (infraRequest *InfraRequest) GetCiScope() *v1.Scope { + return &v1.Scope{ + AppId: infraRequest.appId, + } +} + +func (infraRequest *InfraRequest) GetWorkflowScope() resourceQualifiers.Scope { + return infraRequest.scope +} + +func (infraRequest *InfraRequest) GetAppId() int { + return infraRequest.appId +} + +func (infraRequest *InfraRequest) GetEnvId() int { + return infraRequest.envId +} + +func (infraRequest *InfraRequest) GetTargetPlatforms() []string { + return infraRequest.targetPlatforms +} + +func GetInfraConfigScope(workflowScope resourceQualifiers.Scope) *v1.Scope { + return &v1.Scope{ + AppId: workflowScope.AppId, + } } diff --git a/pkg/pipeline/infraProviders/infraGetters/job/jobInfraGetter.go b/pkg/pipeline/infraProviders/infraGetters/job/jobInfraGetter.go index 5e8417ce7c..4b36be3475 100644 --- a/pkg/pipeline/infraProviders/infraGetters/job/jobInfraGetter.go +++ b/pkg/pipeline/infraProviders/infraGetters/job/jobInfraGetter.go @@ -18,24 +18,72 @@ package job import ( "github.com/caarlos0/env" - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" + apiBean "github.com/devtron-labs/devtron/api/bean" + "github.com/devtron-labs/devtron/pkg/config/read" + "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" + "github.com/devtron-labs/devtron/pkg/infraConfig/service/audit" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters" + "github.com/devtron-labs/devtron/pkg/resourceQualifiers" + "github.com/devtron-labs/devtron/util/sliceUtil" + "go.uber.org/zap" ) -// JobInfraGetter gets infra config for job workflows -type JobInfraGetter struct { - jobInfra bean.InfraConfig +// InfraGetter gets the infra config for job workflows +type InfraGetter struct { + logger *zap.SugaredLogger + jobInfra v1.InfraConfig + configMapService read.ConfigReadService + infraConfigAuditService audit.InfraConfigAuditService } -func NewJobInfraGetter() *JobInfraGetter { - infra := bean.InfraConfig{} - env.Parse(&infra) - return &JobInfraGetter{ - jobInfra: infra, - } +func NewJobInfraGetter(logger *zap.SugaredLogger, + configMapService read.ConfigReadService, + infraConfigAuditService audit.InfraConfigAuditService) (*InfraGetter, error) { + infra := v1.InfraConfig{} + err := env.Parse(&infra) + return &InfraGetter{ + logger: logger, + jobInfra: infra, + configMapService: configMapService, + infraConfigAuditService: infraConfigAuditService, + }, err } -// GetInfraConfigurationsByScope gets infra config for ci workflows using the scope -func (jobInfraGetter JobInfraGetter) GetInfraConfigurationsByScopeAndPlatform(scope *bean.Scope, platform string) (*bean.InfraConfig, error) { +// GetConfigurationsByScopeAndTargetPlatforms gets infra config for ci workflows using the Scope +func (jobInfraGetter *InfraGetter) GetConfigurationsByScopeAndTargetPlatforms(request *infraGetters.InfraRequest) (map[string]*v1.InfraConfig, error) { + response := make(map[string]*v1.InfraConfig) infra := jobInfraGetter.jobInfra - return &infra, nil + configMaps, secrets, err := jobInfraGetter.getCmCsForPrePostStageTrigger(request.GetWorkflowScope(), request.GetAppId(), request.GetEnvId()) + if err != nil { + jobInfraGetter.logger.Errorw("error getting cm/cs for job", "request", request, "error", err) + return response, err + } + infra.ConfigMaps = configMaps.Maps + infra.Secrets = sliceUtil.GetDeReferencedSlice(secrets.Secrets) + response[v1.RUNNER_PLATFORM] = &infra + return response, nil +} + +func (jobInfraGetter *InfraGetter) SaveInfraConfigHistorySnapshot(workflowId int, triggeredBy int32, infraConfigs map[string]*v1.InfraConfig) error { + tx, err := jobInfraGetter.infraConfigAuditService.StartTx() + if err != nil { + jobInfraGetter.logger.Errorw("error in starting the transaction", "err", err) + return err + } + defer jobInfraGetter.infraConfigAuditService.RollbackTx(tx) + err = jobInfraGetter.infraConfigAuditService.SaveCiInfraConfigHistorySnapshot(tx, workflowId, triggeredBy, infraConfigs) + if err != nil { + jobInfraGetter.logger.Errorw("error in creating ci infra trigger snapshot", "infraConfigs", infraConfigs, "err", err) + return err + } + err = tx.Commit() + if err != nil { + jobInfraGetter.logger.Errorw("err in committing transaction", "err", err) + return err + } + return nil +} + +func (jobInfraGetter *InfraGetter) getCmCsForPrePostStageTrigger(scope resourceQualifiers.Scope, appId int, envId int) (*apiBean.ConfigMapJson, *apiBean.ConfigSecretJson, error) { + return jobInfraGetter.configMapService.GetCmCsForPrePostStageTrigger(scope, appId, envId, true) } diff --git a/pkg/pipeline/types/CiCdConfig.go b/pkg/pipeline/types/CiCdConfig.go index 1fd14625df..e404009518 100644 --- a/pkg/pipeline/types/CiCdConfig.go +++ b/pkg/pipeline/types/CiCdConfig.go @@ -23,6 +23,7 @@ import ( "fmt" "github.com/caarlos0/env" blob_storage "github.com/devtron-labs/common-lib/blob-storage" + bean2 "github.com/devtron-labs/common-lib/utils/bean" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" "github.com/devtron-labs/devtron/pkg/bean/common" @@ -558,6 +559,7 @@ type GitTriggerInfoResponse struct { Default bool `json:"default,omitempty"` ImageTaggingData ImageTaggingResponseDTO `json:"imageTaggingData"` Image string `json:"image"` + TargetPlatforms []*bean2.TargetPlatform `json:"targetPlatforms"` } type Trigger struct { diff --git a/pkg/pipeline/types/Workflow.go b/pkg/pipeline/types/Workflow.go index 1e10a66de7..914c732944 100644 --- a/pkg/pipeline/types/Workflow.go +++ b/pkg/pipeline/types/Workflow.go @@ -22,6 +22,7 @@ import ( "github.com/argoproj/argo-workflows/v3/workflow/common" "github.com/devtron-labs/common-lib/blob-storage" "github.com/devtron-labs/common-lib/utils" + bean7 "github.com/devtron-labs/common-lib/utils/bean" "github.com/devtron-labs/common-lib/utils/workFlow" bean3 "github.com/devtron-labs/devtron/api/bean" repository2 "github.com/devtron-labs/devtron/internal/sql/repository" @@ -31,7 +32,7 @@ import ( bean2 "github.com/devtron-labs/devtron/pkg/bean" bean5 "github.com/devtron-labs/devtron/pkg/build/pipeline/bean" repository4 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" - bean6 "github.com/devtron-labs/devtron/pkg/infraConfig/bean" + infraBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" "github.com/devtron-labs/devtron/pkg/pipeline/bean" bean4 "github.com/devtron-labs/devtron/pkg/plugin/bean" "github.com/devtron-labs/devtron/pkg/resourceQualifiers" @@ -160,7 +161,7 @@ func (workflowRequest *WorkflowRequest) updateExternalRunMetadata() { workflowRequest.IsExtRun = true } // Check for external in case of JOB - if env != nil && env.Id != 0 && workflowRequest.CheckForJob() { + if env != nil && env.Id != 0 && workflowRequest.IsDevtronJob() { workflowRequest.EnvironmentId = env.Id workflowRequest.IsExtRun = true } @@ -351,6 +352,11 @@ func (workflowRequest *WorkflowRequest) AddNodeConstraintsFromConfig(workflowTem } +func (workflowRequest *WorkflowRequest) AddInfraConfigurations(workflowTemplate *bean.WorkflowTemplate, infraConfiguration *infraBean.InfraConfig) { + timeout := infraConfiguration.GetCiTimeoutInt() + workflowTemplate.SetActiveDeadlineSeconds(timeout) +} + func (workflowRequest *WorkflowRequest) GetGlobalCmCsNamePrefix() string { switch workflowRequest.Type { case bean.CI_WORKFLOW_PIPELINE_TYPE, bean.JOB_WORKFLOW_PIPELINE_TYPE: @@ -411,10 +417,14 @@ func (workflowRequest *WorkflowRequest) GetExistingCmCsNamePrefix() string { } } -func (workflowRequest *WorkflowRequest) CheckForJob() bool { +func (workflowRequest *WorkflowRequest) IsDevtronJob() bool { return workflowRequest.Type == bean.JOB_WORKFLOW_PIPELINE_TYPE } +func (workflowRequest *WorkflowRequest) IsDevtronCI() bool { + return workflowRequest.Type == bean.CI_WORKFLOW_PIPELINE_TYPE +} + func (workflowRequest *WorkflowRequest) GetNodeConstraints(config *CiCdConfig) *bean.NodeConstraints { nodeLabel, err := GetNodeLabel(config, workflowRequest.Type, workflowRequest.IsExtRun) if err != nil { @@ -442,7 +452,7 @@ func (workflowRequest *WorkflowRequest) GetNodeConstraints(config *CiCdConfig) * } } -func (workflowRequest *WorkflowRequest) GetLimitReqCpuMem(config *CiCdConfig, infraConfigurations *bean6.InfraConfig) v1.ResourceRequirements { +func (workflowRequest *WorkflowRequest) GetLimitReqCpuMem(config *CiCdConfig, infraConfigurations *infraBean.InfraConfig) v1.ResourceRequirements { limitReqCpuMem := &bean.LimitReqCpuMem{} switch workflowRequest.Type { case bean.CI_WORKFLOW_PIPELINE_TYPE, bean.JOB_WORKFLOW_PIPELINE_TYPE: @@ -483,7 +493,7 @@ func (workflowRequest *WorkflowRequest) getWorkflowImage() string { } } -func (workflowRequest *WorkflowRequest) GetWorkflowMainContainer(config *CiCdConfig, infraConfigurations *bean6.InfraConfig, workflowJson []byte, workflowTemplate *bean.WorkflowTemplate, workflowConfigMaps []bean3.ConfigSecretMap, workflowSecrets []bean3.ConfigSecretMap) (v1.Container, error) { +func (workflowRequest *WorkflowRequest) GetWorkflowMainContainer(config *CiCdConfig, infraConfigurations *infraBean.InfraConfig, workflowJson []byte, workflowTemplate *bean.WorkflowTemplate, workflowConfigMaps []bean3.ConfigSecretMap, workflowSecrets []bean3.ConfigSecretMap) (v1.Container, error) { privileged := true pvc := workflowRequest.getPVCForWorkflowRequest() containerEnvVariables := workflowRequest.getContainerEnvVariables(config, workflowJson) @@ -497,6 +507,13 @@ func (workflowRequest *WorkflowRequest) GetWorkflowMainContainer(config *CiCdCon TerminationMessagePath: workFlow.GetTerminalLogFilePath(), Resources: workflowRequest.GetLimitReqCpuMem(config, infraConfigurations), } + // add volumeMount for downwardAPI volume + workflowMainContainer.VolumeMounts = append(workflowMainContainer.VolumeMounts, + v1.VolumeMount{ + Name: utils.DEVTRON_SELF_DOWNWARD_API_VOLUME, + MountPath: utils.DEVTRON_SELF_DOWNWARD_API_VOLUME_PATH, + }, + ) if workflowRequest.Type == bean.CI_WORKFLOW_PIPELINE_TYPE || workflowRequest.Type == bean.JOB_WORKFLOW_PIPELINE_TYPE { workflowMainContainer.Ports = []v1.ContainerPort{{ // exposed for user specific data from ci container @@ -547,7 +564,7 @@ func (workflowRequest *WorkflowRequest) updateVolumeMountsForCi(config *CiCdConf return err } workflowTemplate.Volumes = append(workflowTemplate.Volumes, volume...) - workflowMainContainer.VolumeMounts = volumeMounts + workflowMainContainer.VolumeMounts = append(workflowMainContainer.VolumeMounts, volumeMounts...) return nil } @@ -660,6 +677,7 @@ type WorkflowResponse struct { CustomTag *bean3.CustomTagErrorResponse `json:"customTag,omitempty"` PipelineType string `json:"pipelineType"` ReferenceWorkflowId int `json:"referenceWorkflowId"` + TargetPlatforms []*bean7.TargetPlatform `json:"targetPlatforms"` } type ConfigMapSecretDto struct { diff --git a/pkg/pipeline/types/Workflow_ent.go b/pkg/pipeline/types/Workflow_ent.go new file mode 100644 index 0000000000..2a5c03e78f --- /dev/null +++ b/pkg/pipeline/types/Workflow_ent.go @@ -0,0 +1,35 @@ +package types + +import ( + bean2 "github.com/devtron-labs/common-lib/imageScan/bean" + "github.com/devtron-labs/devtron/pkg/pipeline/bean" +) + +type ImageScanningSteps struct { + Steps []*bean.StepObject `json:"steps"` + ScanToolId int `json:"scanToolId"` +} + +func NewImageScanningStepsDto() *ImageScanningSteps { + return &ImageScanningSteps{} +} + +func (r *ImageScanningSteps) WithSteps(steps []*bean.StepObject) *ImageScanningSteps { + return r +} + +func (r *ImageScanningSteps) WithScanToolId(scanToolId int) *ImageScanningSteps { + return r +} + +func (workflowRequest *WorkflowRequest) SetExecuteImageScanningVia(scanVia bean2.ScanExecutionMedium) { + return +} + +func (workflowRequest *WorkflowRequest) SetImageScanningSteps(imageScanningSteps []*ImageScanningSteps) { + return +} + +func (workflowRequest *WorkflowRequest) SetAwsInspectorConfig(awsInspectorConfig string) { + return +} diff --git a/pkg/plugin/GlobalPluginService.go b/pkg/plugin/GlobalPluginService.go index cdbbff8670..d6d663d6a5 100644 --- a/pkg/plugin/GlobalPluginService.go +++ b/pkg/plugin/GlobalPluginService.go @@ -74,6 +74,7 @@ type GlobalPluginService interface { PatchPlugin(pluginDto *bean2.PluginMetadataDto, userId int32) (*bean2.PluginMetadataDto, error) GetDetailedPluginInfoByPluginId(pluginId int) (*bean2.PluginMetadataDto, error) GetAllDetailedPluginInfo() ([]*bean2.PluginMetadataDto, error) + GetNewPluginStepsDtoByRefPluginIdentifier(identifier string) (*bean2.PluginStepsDto, error) CreatePluginOrVersions(pluginDto *bean2.PluginParentMetadataDto, userId int32) (int, error) ListAllPluginsV2(filter *bean2.PluginsListFilter) (*bean2.PluginsDto, error) @@ -1940,7 +1941,7 @@ func (impl *GlobalPluginServiceImpl) MigratePluginDataToParentPluginMetadata(plu continue } parentMetadata := repository.NewPluginParentMetadata() - parentMetadata.SetParentPluginMetadata(pluginMetadata).CreateAuditLog(bean.SystemUserId) + parentMetadata.SetParentPluginMetadata(pluginMetadata).CreateAuditLog(bean.SystemUserId).WithIsExposed(true) parentMetadata.Identifier = identifier parentMetadata, err = impl.globalPluginRepository.SavePluginParentMetadata(tx, parentMetadata) if err != nil { @@ -2134,7 +2135,7 @@ func (impl *GlobalPluginServiceImpl) createNewPlugin(tx *pg.Tx, pluginDto *bean2 pluginStageMapping := &repository.PluginStageMapping{ PluginId: pluginParentMetadata.Id, - StageType: repository.CI_CD, + StageType: pluginDto.GetPluginStageType(), AuditLog: sql.NewDefaultAuditLog(userId), } _, err = impl.globalPluginRepository.SavePluginStageMapping(pluginStageMapping, tx) @@ -2329,3 +2330,13 @@ func validatePluginVariable(variable *bean2.PluginVariableDto) error { } return nil } + +func (impl *GlobalPluginServiceImpl) GetNewPluginStepsDtoByRefPluginIdentifier(identifier string) (*bean2.PluginStepsDto, error) { + pluginMetadata, err := impl.globalPluginRepository.GetPluginMetadataByPluginIdentifier(identifier) + if err != nil { + impl.logger.Errorw("error in getting plugin steps by plugin identifier", "identifier", identifier, "err", err) + return nil, err + } + pluginStepDto := adaptor.GetNewPluginStepDtoFromRefPluginMetadata(pluginMetadata) + return pluginStepDto, nil +} diff --git a/pkg/plugin/adaptor/adaptor.go b/pkg/plugin/adaptor/adaptor.go index 06e06d4048..e145f766d0 100644 --- a/pkg/plugin/adaptor/adaptor.go +++ b/pkg/plugin/adaptor/adaptor.go @@ -8,12 +8,12 @@ import ( func GetPluginParentMetadataDbObject(pluginDto *pluginBean.PluginParentMetadataDto, userId int32) *repository.PluginParentMetadata { return repository.NewPluginParentMetadata().CreateAuditLog(userId). - WithBasicMetadata(pluginDto.Name, pluginDto.PluginIdentifier, pluginDto.Description, pluginDto.Icon, repository.PLUGIN_TYPE_SHARED) + WithBasicMetadata(pluginDto.Name, pluginDto.PluginIdentifier, pluginDto.Description, pluginDto.Icon, repository.PLUGIN_TYPE_SHARED, pluginDto.IsExposed) } func GetPluginVersionMetadataDbObject(pluginDto *pluginBean.PluginParentMetadataDto, userId int32) *repository.PluginMetadata { versionDto := pluginDto.Versions.DetailedPluginVersionData[0] - return repository.NewPluginVersionMetadata().CreateAuditLog(userId).WithBasicMetadata(pluginDto.Name, versionDto.Description, versionDto.Version, versionDto.DocLink) + return repository.NewPluginVersionMetadata().CreateAuditLog(userId).WithBasicMetadata(pluginDto.Name, versionDto.Description, versionDto.Version, versionDto.DocLink, versionDto.IsExposed) } func GetPluginStepDbObject(pluginStepDto *pluginBean.PluginStepsDto, pluginVersionMetadataId int, userId int32) *repository.PluginStep { @@ -22,7 +22,7 @@ func GetPluginStepDbObject(pluginStepDto *pluginBean.PluginStepsDto, pluginVersi Name: pluginStepDto.Name, Description: pluginStepDto.Description, Index: 1, - StepType: repository.PLUGIN_STEP_TYPE_INLINE, + StepType: pluginStepDto.GetStepType(), RefPluginId: pluginStepDto.RefPluginId, OutputDirectoryPath: pluginStepDto.OutputDirectoryPath, DependentOnStep: pluginStepDto.DependentOnStep, @@ -79,3 +79,133 @@ func GetPluginStepConditionDbObject(stepDataId, pluginStepVariableId int, plugin AuditLog: sql.NewDefaultAuditLog(userId), } } + +// Below adaptors contains reverse adaptors of db object adaptors + +// GetPluginStepDtoFromDbObject returns PluginStepsDto object without PluginVariableDto and PluginPipelineScript objects +func GetPluginStepDtoFromDbObject(pluginStepsDbObj *repository.PluginStep) *pluginBean.PluginStepsDto { + if pluginStepsDbObj == nil { + return &pluginBean.PluginStepsDto{} + } + return &pluginBean.PluginStepsDto{ + Id: pluginStepsDbObj.Id, + Name: pluginStepsDbObj.Name, + Description: pluginStepsDbObj.Description, + Index: pluginStepsDbObj.Index, + StepType: pluginStepsDbObj.StepType, + RefPluginId: pluginStepsDbObj.RefPluginId, + OutputDirectoryPath: pluginStepsDbObj.OutputDirectoryPath, + DependentOnStep: pluginStepsDbObj.DependentOnStep, + ScriptId: pluginStepsDbObj.ScriptId, + } +} + +// GetPluginStepsDtoFromDbObjects takes pluginStepsDbObj array and returns transformed array of pluginSteps dto object +func GetPluginStepsDtoFromDbObjects(pluginStepsDbObj []*repository.PluginStep) []*pluginBean.PluginStepsDto { + pluginStepsDto := make([]*pluginBean.PluginStepsDto, 0, len(pluginStepsDbObj)) + for _, pluginStep := range pluginStepsDbObj { + pluginStepsDto = append(pluginStepsDto, GetPluginStepDtoFromDbObject(pluginStep)) + } + return pluginStepsDto +} + +// GetPluginStepVarsDtoFromDbObject returns PluginVariableDto object wihtout pluginStepConditions +func GetPluginStepVarsDtoFromDbObject(pluginStepVarDbObj *repository.PluginStepVariable) *pluginBean.PluginVariableDto { + if pluginStepVarDbObj == nil { + return &pluginBean.PluginVariableDto{} + } + return &pluginBean.PluginVariableDto{ + Id: pluginStepVarDbObj.Id, + Name: pluginStepVarDbObj.Name, + Format: pluginStepVarDbObj.Format, + Description: pluginStepVarDbObj.Description, + IsExposed: pluginStepVarDbObj.IsExposed, + AllowEmptyValue: pluginStepVarDbObj.AllowEmptyValue, + DefaultValue: pluginStepVarDbObj.DefaultValue, + Value: pluginStepVarDbObj.Value, + VariableType: pluginStepVarDbObj.VariableType, + ValueType: pluginStepVarDbObj.ValueType, + PreviousStepIndex: pluginStepVarDbObj.PreviousStepIndex, + VariableStepIndex: pluginStepVarDbObj.VariableStepIndex, + VariableStepIndexInPlugin: pluginStepVarDbObj.VariableStepIndexInPlugin, + ReferenceVariableName: pluginStepVarDbObj.ReferenceVariableName, + PluginStepId: pluginStepVarDbObj.PluginStepId, + } +} + +// GetPluginStepVariablesDtoFromDbObjects takes pluginStepVarsDbObj array and returns transformed array of pluginVariable dto object +func GetPluginStepVariablesDtoFromDbObjects(pluginStepVarsDbObj []*repository.PluginStepVariable) []*pluginBean.PluginVariableDto { + pluginStepVarsDto := make([]*pluginBean.PluginVariableDto, 0, len(pluginStepVarsDbObj)) + for _, pluginStepVar := range pluginStepVarsDbObj { + pluginStepVarsDto = append(pluginStepVarsDto, GetPluginStepVarsDtoFromDbObject(pluginStepVar)) + } + return pluginStepVarsDto +} + +// GetPluginPipelineScriptDtoFromDbObject returns PluginPipelineScript dto object without ScriptPathArgPortMapping object +func GetPluginPipelineScriptDtoFromDbObject(pluginPipelineScript *repository.PluginPipelineScript) *pluginBean.PluginPipelineScript { + if pluginPipelineScript == nil { + return &pluginBean.PluginPipelineScript{} + } + return &pluginBean.PluginPipelineScript{ + Id: pluginPipelineScript.Id, + Script: pluginPipelineScript.Script, + StoreScriptAt: pluginPipelineScript.StoreScriptAt, + Type: pluginPipelineScript.Type, + DockerfileExists: pluginPipelineScript.DockerfileExists, + MountPath: pluginPipelineScript.MountPath, + MountCodeToContainer: pluginPipelineScript.MountCodeToContainer, + MountCodeToContainerPath: pluginPipelineScript.MountCodeToContainerPath, + MountDirectoryFromHost: pluginPipelineScript.MountDirectoryFromHost, + ContainerImagePath: pluginPipelineScript.ContainerImagePath, + ImagePullSecretType: pluginPipelineScript.ImagePullSecretType, + ImagePullSecret: pluginPipelineScript.ImagePullSecret, + } +} + +// GetPluginPipelineScriptsDtoFromDbObjects takes pluginPipelineScriptDbObjs array and returns transformed array of pluginPipelineScripts dto object +func GetPluginPipelineScriptsDtoFromDbObjects(pluginPipelineScriptDbObjs []*repository.PluginPipelineScript) []*pluginBean.PluginPipelineScript { + pluginPipelineScriptsDto := make([]*pluginBean.PluginPipelineScript, 0, len(pluginPipelineScriptDbObjs)) + for _, script := range pluginPipelineScriptDbObjs { + pluginPipelineScriptsDto = append(pluginPipelineScriptsDto, GetPluginPipelineScriptDtoFromDbObject(script)) + } + return pluginPipelineScriptsDto +} + +func GetScripPathArgPortMappingDtoFromDbObject(scripPathArgPortMappingDbObj *repository.ScriptPathArgPortMapping) *pluginBean.ScriptPathArgPortMapping { + if scripPathArgPortMappingDbObj == nil { + return &pluginBean.ScriptPathArgPortMapping{} + } + return &pluginBean.ScriptPathArgPortMapping{ + Id: scripPathArgPortMappingDbObj.Id, + TypeOfMapping: scripPathArgPortMappingDbObj.TypeOfMapping, + FilePathOnDisk: scripPathArgPortMappingDbObj.FilePathOnDisk, + FilePathOnContainer: scripPathArgPortMappingDbObj.FilePathOnContainer, + Command: scripPathArgPortMappingDbObj.Command, + Args: scripPathArgPortMappingDbObj.Args, + PortOnLocal: scripPathArgPortMappingDbObj.PortOnLocal, + PortOnContainer: scripPathArgPortMappingDbObj.PortOnContainer, + ScriptId: scripPathArgPortMappingDbObj.ScriptId, + } +} + +// GetScripPathArgPortMappingsDtoFromDbObjects takes scripPathArgPortMappingsDbObj array and returns transformed array of scriptPathArgPortMapping dto object +func GetScripPathArgPortMappingsDtoFromDbObjects(scripPathArgPortMappingsDbObj []*repository.ScriptPathArgPortMapping) []*pluginBean.ScriptPathArgPortMapping { + scripPathArgPortMappingsDto := make([]*pluginBean.ScriptPathArgPortMapping, 0, len(scripPathArgPortMappingsDbObj)) + for _, mapping := range scripPathArgPortMappingsDbObj { + scripPathArgPortMappingsDto = append(scripPathArgPortMappingsDto, GetScripPathArgPortMappingDtoFromDbObject(mapping)) + } + return scripPathArgPortMappingsDto +} + +func GetNewPluginStepDtoFromRefPluginMetadata(refPluginMetadata *repository.PluginMetadata) *pluginBean.PluginStepsDto { + if refPluginMetadata == nil { + return &pluginBean.PluginStepsDto{} + } + return &pluginBean.PluginStepsDto{ + Name: refPluginMetadata.Name, + Description: refPluginMetadata.Description, + StepType: repository.PLUGIN_STEP_TYPE_REF_PLUGIN, + RefPluginId: refPluginMetadata.Id, + } +} diff --git a/pkg/plugin/bean/bean.go b/pkg/plugin/bean/bean.go index abe73741a3..2434d375ce 100644 --- a/pkg/plugin/bean/bean.go +++ b/pkg/plugin/bean/bean.go @@ -54,6 +54,7 @@ type PluginMetadataDto struct { PluginStage string `json:"pluginStage,omitempty"` PluginSteps []*PluginStepsDto `json:"pluginSteps,omitempty"` AreNewTagsPresent bool `json:"areNewTagsPresent,omitempty"` + IsExposed *bool `json:"-"` } type PluginMinDto struct { @@ -125,13 +126,22 @@ type PluginParentMetadataDto struct { Description string `json:"description" validate:"max=300"` Type string `json:"type,omitempty" validate:"oneof=SHARED PRESET"` Icon string `json:"icon,omitempty"` + PluginStageType string `json:"pluginStageType,omitempty"` Versions *PluginVersions `json:"pluginVersions"` + IsExposed *bool `json:"-"` } func NewPluginParentMetadataDto() *PluginParentMetadataDto { return &PluginParentMetadataDto{} } +func (r *PluginParentMetadataDto) GetPluginStageType() int { + if r.PluginStageType == repository.SCANNER_STAGE_TYPE { + return repository.SCANNER + } + return repository.CI_CD +} + func (r *PluginParentMetadataDto) WithNameAndId(name string, id int) *PluginParentMetadataDto { r.Id = id r.Name = name @@ -299,6 +309,19 @@ type PluginStepsDto struct { DependentOnStep string `json:"dependentOnStep"` PluginStepVariable []*PluginVariableDto `json:"pluginStepVariable,omitempty"` PluginPipelineScript *PluginPipelineScript `json:"pluginPipelineScript,omitempty"` + ScriptId int `json:"-"` +} + +// GetStepType returns stepType if present in PluginStepsDto else returns PLUGIN_STEP_TYPE_INLINE as default stepType +func (r *PluginStepsDto) GetStepType() repository.PluginStepType { + if len(r.StepType) > 0 { + return r.StepType + } + return repository.PLUGIN_STEP_TYPE_INLINE +} + +func (r *PluginStepsDto) ID() int { + return r.Id } type PluginVariableDto struct { @@ -317,6 +340,7 @@ type PluginVariableDto struct { VariableStepIndexInPlugin int `json:"variableStepIndexInPlugin"` ReferenceVariableName string `json:"referenceVariableName,omitempty"` PluginStepCondition []*PluginStepCondition `json:"pluginStepCondition,omitempty"` + PluginStepId int `json:"-"` } func (s *PluginVariableDto) GetValue() string { diff --git a/pkg/plugin/helper/helper.go b/pkg/plugin/helper/helper.go index 390c77733c..42cbfaf0e6 100644 --- a/pkg/plugin/helper/helper.go +++ b/pkg/plugin/helper/helper.go @@ -116,3 +116,49 @@ func GetPluginVersionsMetadataByVersionAndParentPluginIds(pluginVersionsMetadata } return filteredPluginVersionMetadata } + +type IdGetter interface { + // ID gets id field from struct wherever this interface is implemented, see PluginStep sql object for example + ID() int +} + +// GetIDs is a generic function to get IDs +func GetIDs[T IdGetter](items []T) []int { + ids := make([]int, len(items)) + for i, item := range items { + ids[i] = item.ID() + } + return ids +} + +func GetPluginStepIdVsPluginStepVariablesMap(pluginStepVariables []*bean.PluginVariableDto) map[int][]*bean.PluginVariableDto { + pluginStepIdVsPluginStepVariablesMap := make(map[int][]*bean.PluginVariableDto, len(pluginStepVariables)) + for _, stepVar := range pluginStepVariables { + pluginStepIdVsPluginStepVariablesMap[stepVar.PluginStepId] = append(pluginStepIdVsPluginStepVariablesMap[stepVar.PluginStepId], stepVar) + } + return pluginStepIdVsPluginStepVariablesMap +} + +func GetScriptIdVsScriptArgsDetailsMap(scriptArgDetails []*bean.ScriptPathArgPortMapping) map[int][]*bean.ScriptPathArgPortMapping { + scriptIdVsScriptArgsDetailsMap := make(map[int][]*bean.ScriptPathArgPortMapping, len(scriptArgDetails)) + for _, scriptArgDetail := range scriptArgDetails { + scriptIdVsScriptArgsDetailsMap[scriptArgDetail.ScriptId] = append(scriptIdVsScriptArgsDetailsMap[scriptArgDetail.ScriptId], scriptArgDetail) + } + return scriptIdVsScriptArgsDetailsMap +} + +func GetScriptIdList(stepsDto []*bean.PluginStepsDto) []int { + scriptIds := make([]int, 0, len(stepsDto)) + for _, step := range stepsDto { + scriptIds = append(scriptIds, step.ScriptId) + } + return scriptIds +} + +func GetScriptIdVsPluginScript(pluginScripts []*bean.PluginPipelineScript) map[int]*bean.PluginPipelineScript { + scriptIdVsPluginScript := make(map[int]*bean.PluginPipelineScript, len(pluginScripts)) + for _, pluginScript := range pluginScripts { + scriptIdVsPluginScript[pluginScript.Id] = pluginScript + } + return scriptIdVsPluginScript +} diff --git a/pkg/plugin/repository/GlobalPluginRepository.go b/pkg/plugin/repository/GlobalPluginRepository.go index f8a31966a5..715b74fcc0 100644 --- a/pkg/plugin/repository/GlobalPluginRepository.go +++ b/pkg/plugin/repository/GlobalPluginRepository.go @@ -93,14 +93,16 @@ const ( ) const ( - CI = 1 - CD = 2 - CI_CD = 3 - CD_STAGE_TYPE = "cd" - CI_STAGE_TYPE = "ci" - CI_CD_STAGE_TYPE = "ci_cd" - EXISTING_TAG_TYPE = "existing_tags" - NEW_TAG_TYPE = "new_tags" + CI = 1 + CD = 2 + CI_CD = 3 + SCANNER = 4 + CD_STAGE_TYPE = "cd" + CI_STAGE_TYPE = "ci" + CI_CD_STAGE_TYPE = "ci_cd" + SCANNER_STAGE_TYPE = "scanner" + EXISTING_TAG_TYPE = "existing_tags" + NEW_TAG_TYPE = "new_tags" ) type PluginParentMetadata struct { @@ -112,6 +114,7 @@ type PluginParentMetadata struct { Type PluginType `sql:"type"` Icon string `sql:"icon"` Deleted bool `sql:"deleted, notnull"` + IsExposed bool `sql:"is_exposed, notnull"` // it's not user driven, used internally to make decision weather to show plugin or not in plugin list sql.AuditLog } @@ -126,14 +129,24 @@ func (r *PluginParentMetadata) CreateAuditLog(userId int32) *PluginParentMetadat r.UpdatedOn = time.Now() return r } +func (r *PluginParentMetadata) WithIsExposed(isExposed bool) *PluginParentMetadata { + r.IsExposed = isExposed + return r +} -func (r *PluginParentMetadata) WithBasicMetadata(name, identifier, description, icon string, pluginType PluginType) *PluginParentMetadata { +func (r *PluginParentMetadata) WithBasicMetadata(name, identifier, description, icon string, pluginType PluginType, isExposed *bool) *PluginParentMetadata { r.Name = name r.Identifier = identifier r.Description = description r.Icon = icon r.Type = pluginType r.Deleted = false + if isExposed != nil { + r.IsExposed = *isExposed + } else { + //default set true + r.IsExposed = true + } return r } @@ -170,6 +183,7 @@ type PluginMetadata struct { IsDeprecated bool `sql:"is_deprecated, notnull"` DocLink string `sql:"doc_link"` IsLatest bool `sql:"is_latest, notnull"` + IsExposed bool `sql:"is_exposed, notnull"` // it's not user driven, used internally to make decision weather to show plugin or not in plugin list sql.AuditLog } @@ -185,13 +199,19 @@ func (r *PluginMetadata) CreateAuditLog(userId int32) *PluginMetadata { return r } -func (r *PluginMetadata) WithBasicMetadata(name, description, pluginVersion, docLink string) *PluginMetadata { +func (r *PluginMetadata) WithBasicMetadata(name, description, pluginVersion, docLink string, isExposed *bool) *PluginMetadata { r.Name = name r.PluginVersion = pluginVersion r.Description = description r.DocLink = docLink r.Deleted = false r.IsDeprecated = false + if isExposed != nil { + r.IsExposed = *isExposed + } else { + //default value is true + r.IsExposed = true + } return r } @@ -357,8 +377,11 @@ type GlobalPluginRepository interface { GetPluginTagByNames(tagNames []string) ([]*PluginTag, error) GetAllPluginTagRelations() ([]*PluginTagRelation, error) GetScriptDetailById(id int) (*PluginPipelineScript, error) + GetScriptDetailByIds(ids []int) ([]*PluginPipelineScript, error) GetScriptMappingDetailByScriptId(scriptId int) ([]*ScriptPathArgPortMapping, error) + GetScriptMappingDetailByScriptIds(scriptIds []int) ([]*ScriptPathArgPortMapping, error) GetVariablesByStepId(stepId int) ([]*PluginStepVariable, error) + GetVariablesByStepIds(stepIds []int) ([]*PluginStepVariable, error) GetStepsByPluginIds(pluginIds []int) ([]*PluginStep, error) GetExposedVariablesByPluginIdAndVariableType(pluginId int, variableType PluginStepVariableType) ([]*PluginStepVariable, error) GetExposedVariablesByPluginId(pluginId int) ([]*PluginStepVariable, error) @@ -380,6 +403,7 @@ type GlobalPluginRepository interface { GetAllPluginMinDataByType(pluginType string) ([]*PluginParentMetadata, error) GetPluginParentMinDataById(id int) (*PluginParentMetadata, error) MarkPreviousPluginVersionLatestFalse(pluginParentId int) error + GetPluginMetadataByPluginIdentifier(identifier string) (*PluginMetadata, error) SavePluginMetadata(pluginMetadata *PluginMetadata, tx *pg.Tx) (*PluginMetadata, error) SavePluginStageMapping(pluginStageMapping *PluginStageMapping, tx *pg.Tx) (*PluginStageMapping, error) @@ -429,6 +453,7 @@ func (impl *GlobalPluginRepositoryImpl) GetMetaDataForAllPlugins(excludeDeprecat var plugins []*PluginMetadata query := impl.dbConnection.Model(&plugins). Where("deleted = ?", false). + Where("is_exposed = ?", true). Order("id") if excludeDeprecated { query = query.Where("is_deprecated = ?", false) @@ -538,6 +563,18 @@ func (impl *GlobalPluginRepositoryImpl) GetScriptDetailById(id int) (*PluginPipe return &scriptDetail, nil } +func (impl *GlobalPluginRepositoryImpl) GetScriptDetailByIds(ids []int) ([]*PluginPipelineScript, error) { + var scriptDetail []*PluginPipelineScript + err := impl.dbConnection.Model(&scriptDetail). + Where("id in (?)", pg.In(ids)). + Where("deleted = ?", false).Select() + if err != nil { + impl.logger.Errorw("err in getting script detail by ids", "ids", ids, "err", err) + return nil, err + } + return scriptDetail, nil +} + func (impl *GlobalPluginRepositoryImpl) GetScriptMappingDetailByScriptId(scriptId int) ([]*ScriptPathArgPortMapping, error) { var scriptMappingDetail []*ScriptPathArgPortMapping err := impl.dbConnection.Model(&scriptMappingDetail). @@ -550,6 +587,18 @@ func (impl *GlobalPluginRepositoryImpl) GetScriptMappingDetailByScriptId(scriptI return scriptMappingDetail, nil } +func (impl *GlobalPluginRepositoryImpl) GetScriptMappingDetailByScriptIds(scriptIds []int) ([]*ScriptPathArgPortMapping, error) { + var scriptMappingDetail []*ScriptPathArgPortMapping + err := impl.dbConnection.Model(&scriptMappingDetail). + Where("script_id in (?)", pg.In(scriptIds)). + Where("deleted = ?", false).Select() + if err != nil { + impl.logger.Errorw("err in getting script mapping detail by id", "scriptIds", scriptIds, "err", err) + return nil, err + } + return scriptMappingDetail, nil +} + func (impl *GlobalPluginRepositoryImpl) GetVariablesByStepId(stepId int) ([]*PluginStepVariable, error) { var variables []*PluginStepVariable err := impl.dbConnection.Model(&variables). @@ -562,6 +611,18 @@ func (impl *GlobalPluginRepositoryImpl) GetVariablesByStepId(stepId int) ([]*Plu return variables, nil } +func (impl *GlobalPluginRepositoryImpl) GetVariablesByStepIds(stepIds []int) ([]*PluginStepVariable, error) { + var variables []*PluginStepVariable + err := impl.dbConnection.Model(&variables). + Where("plugin_step_id in (?)", pg.In(stepIds)). + Where("deleted = ?", false).Select() + if err != nil { + impl.logger.Errorw("err in getting variables by stepIds", "stepIds", stepIds, "err", err) + return nil, err + } + return variables, nil +} + func (impl *GlobalPluginRepositoryImpl) GetExposedVariablesByPluginIdAndVariableType(pluginId int, variableType PluginStepVariableType) ([]*PluginStepVariable, error) { var pluginVariables []*PluginStepVariable err := impl.dbConnection.Model(&pluginVariables). @@ -886,7 +947,7 @@ func (impl *GlobalPluginRepositoryImpl) GetAllFilteredPluginParentMetadata(searc var plugins []*PluginParentMetadata query := "select ppm.id, ppm.identifier,ppm.name,ppm.description,ppm.type,ppm.icon,ppm.deleted,ppm.created_by, ppm.created_on,ppm.updated_by,ppm.updated_on from plugin_parent_metadata ppm" + " inner join plugin_metadata pm on pm.plugin_parent_metadata_id=ppm.id" - whereCondition := fmt.Sprintf(" where ppm.deleted=false AND pm.deleted=false AND pm.is_latest=true and pm.is_deprecated=false") + whereCondition := fmt.Sprintf(" where ppm.deleted=false AND pm.deleted=false AND pm.is_latest=true AND pm.is_deprecated=false AND pm.is_exposed=true AND ppm.is_exposed=true") if len(tags) > 0 { tagFilterSubQuery := fmt.Sprintf("select ptr.plugin_id from plugin_tag_relation ptr inner join plugin_tag pt on ptr.tag_id =pt.id where pt.deleted =false and pt.name in (%s) group by ptr.plugin_id having count(ptr.plugin_id )=%d", helper.GetCommaSepratedStringWithComma(tags), len(tags)) whereCondition += fmt.Sprintf(" AND pm.id in (%s)", tagFilterSubQuery) @@ -926,7 +987,8 @@ func (impl *GlobalPluginRepositoryImpl) GetAllPluginMinDataByType(pluginType str var plugins []*PluginParentMetadata query := impl.dbConnection.Model(&plugins). Column("plugin_parent_metadata.id", "plugin_parent_metadata.name", "plugin_parent_metadata.type", "plugin_parent_metadata.icon", "plugin_parent_metadata.identifier"). - Where("deleted = ?", false) + Where("deleted = ?", false). + Where("is_exposed = ?", true) if len(pluginType) != 0 { query.Where("type = ?", pluginType) } @@ -950,3 +1012,19 @@ func (impl *GlobalPluginRepositoryImpl) MarkPreviousPluginVersionLatestFalse(plu } return nil } + +func (impl *GlobalPluginRepositoryImpl) GetPluginMetadataByPluginIdentifier(identifier string) (*PluginMetadata, error) { + pluginMetadata := &PluginMetadata{} + err := impl.dbConnection.Model(pluginMetadata). + Join("INNER JOIN plugin_parent_metadata ppm"). + JoinOn("plugin_metadata.plugin_parent_metadata_id = ppm.id"). + Where("ppm.deleted = ?", false). + Where("plugin_metadata.deleted = ?", false). + Where("ppm.identifier = ?", identifier). + Select() + if err != nil { + impl.logger.Errorw("err in getting plugin metadata by plugin identifier", "identifier", identifier, "err", err) + return nil, err + } + return pluginMetadata, nil +} diff --git a/pkg/policyGovernance/security/imageScanning/ImageScanService.go b/pkg/policyGovernance/security/imageScanning/ImageScanService.go index c456c21a39..f0268c20a8 100644 --- a/pkg/policyGovernance/security/imageScanning/ImageScanService.go +++ b/pkg/policyGovernance/security/imageScanning/ImageScanService.go @@ -23,11 +23,11 @@ import ( "github.com/devtron-labs/devtron/pkg/cluster/environment" "github.com/devtron-labs/devtron/pkg/cluster/environment/bean" bean2 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/bean" - "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/adapter" bean3 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/bean" "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/helper/parser" repository3 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" securityBean "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository/bean" + repository2 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/repository" "github.com/devtron-labs/devtron/pkg/workflow/cd/read" "go.opentelemetry.io/otel" "time" @@ -68,7 +68,7 @@ type ImageScanServiceImpl struct { policyService PolicyService pipelineRepository pipelineConfig.PipelineRepository ciPipelineRepository pipelineConfig.CiPipelineRepository - scanToolMetaDataRepository repository3.ScanToolMetadataRepository + scanToolMetaDataRepository repository2.ScanToolMetadataRepository scanToolExecutionHistoryMappingRepository repository3.ScanToolExecutionHistoryMappingRepository cvePolicyRepository repository3.CvePolicyRepository cdWorkflowReadService read.CdWorkflowReadService @@ -80,7 +80,7 @@ func NewImageScanServiceImpl(Logger *zap.SugaredLogger, scanHistoryRepository re userService user.UserService, appRepository repository1.AppRepository, envService environment.EnvironmentService, ciArtifactRepository repository.CiArtifactRepository, policyService PolicyService, - pipelineRepository pipelineConfig.PipelineRepository, ciPipelineRepository pipelineConfig.CiPipelineRepository, scanToolMetaDataRepository repository3.ScanToolMetadataRepository, scanToolExecutionHistoryMappingRepository repository3.ScanToolExecutionHistoryMappingRepository, + pipelineRepository pipelineConfig.PipelineRepository, ciPipelineRepository pipelineConfig.CiPipelineRepository, scanToolMetaDataRepository repository2.ScanToolMetadataRepository, scanToolExecutionHistoryMappingRepository repository3.ScanToolExecutionHistoryMappingRepository, cvePolicyRepository repository3.CvePolicyRepository, cdWorkflowReadService read.CdWorkflowReadService) *ImageScanServiceImpl { return &ImageScanServiceImpl{Logger: Logger, scanHistoryRepository: scanHistoryRepository, scanResultRepository: scanResultRepository, @@ -485,12 +485,13 @@ func (impl ImageScanServiceImpl) FetchExecutionDetailResult(request *bean3.Image } // setting scan tool name if scan tool id is present if imageScanResponse.ScanToolId > 0 { - scanToolName, err := impl.scanToolMetaDataRepository.FindNameById(imageScanResponse.ScanToolId) + scanToolName, scanToolUrl, err := impl.scanToolMetaDataRepository.FindNameAndUrlById(imageScanResponse.ScanToolId) if err != nil { impl.Logger.Errorw("error in getting scan tool name by id", "scanToolId", imageScanResponse.ScanToolId, "err", err) return nil, err } imageScanResponse.ScanToolName = scanToolName + imageScanResponse.ScanToolUrl = scanToolUrl } return imageScanResponse, nil } @@ -717,22 +718,6 @@ func (impl ImageScanServiceImpl) IsImageScanExecutionCompleted(image, imageDiges return isScanningCompleted, nil } -func (impl ImageScanServiceImpl) GetScanResults(resourceScanQueryParams *bean3.ResourceScanQueryParams) (resp parser.ResourceScanResponseDto, err error) { - request := &bean3.ImageScanRequest{ - ArtifactId: resourceScanQueryParams.ArtifactId, - AppId: resourceScanQueryParams.AppId, - EnvId: resourceScanQueryParams.EnvId, - } - respFromExecutionDetail, err := impl.FetchExecutionDetailResult(request) - if err != nil { - impl.Logger.Errorw("error encountered in GetScanResults", "req", request, "err", err) - return resp, err - } - // build an adapter to convert the respFromExecutionDetail to the required ResourceScanResponseDto format - return adapter.ExecutionDetailsToResourceScanResponseDto(respFromExecutionDetail), nil - -} - func (impl ImageScanServiceImpl) FilterDeployInfoByScannedArtifactsDeployedInEnv(deployInfoList []*repository3.ImageScanDeployInfo) ([]*repository3.ImageScanDeployInfo, error) { filteredDeployInfoList := make([]*repository3.ImageScanDeployInfo, 0, len(deployInfoList)) appVsEnvIdMap := make(map[int][]int, len(deployInfoList)) diff --git a/pkg/policyGovernance/security/imageScanning/ImageScanService_ent.go b/pkg/policyGovernance/security/imageScanning/ImageScanService_ent.go new file mode 100644 index 0000000000..906c0fe0b4 --- /dev/null +++ b/pkg/policyGovernance/security/imageScanning/ImageScanService_ent.go @@ -0,0 +1,23 @@ +package imageScanning + +import ( + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/adapter" + bean3 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/bean" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/helper/parser" +) + +func (impl ImageScanServiceImpl) GetScanResults(resourceScanQueryParams *bean3.ResourceScanQueryParams) (resp parser.ResourceScanResponseDto, err error) { + request := &bean3.ImageScanRequest{ + ArtifactId: resourceScanQueryParams.ArtifactId, + AppId: resourceScanQueryParams.AppId, + EnvId: resourceScanQueryParams.EnvId, + } + respFromExecutionDetail, err := impl.FetchExecutionDetailResult(request) + if err != nil { + impl.Logger.Errorw("error encountered in GetScanResults", "req", request, "err", err) + return resp, err + } + // build an adapter to convert the respFromExecutionDetail to the required ResourceScanResponseDto format + return adapter.ExecutionDetailsToResourceScanResponseDto(respFromExecutionDetail), nil + +} diff --git a/pkg/policyGovernance/security/imageScanning/adapter/adapter.go b/pkg/policyGovernance/security/imageScanning/adapter/adapter.go index 8f63554e7f..034220baff 100644 --- a/pkg/policyGovernance/security/imageScanning/adapter/adapter.go +++ b/pkg/policyGovernance/security/imageScanning/adapter/adapter.go @@ -41,11 +41,12 @@ func BuildImageVulnerabilityResponse(image string, vulnerabilities parser.Vulner return &parser.ImageVulnerability{Image: image, Vulnerabilities: vulnerabilities, Metadata: metadata} } -func BuildMetadata(status string, startedOn time.Time, scanToolName string) *parser.Metadata { +func BuildMetadata(status string, startedOn time.Time, scanToolName string, scanToolUrl string) *parser.Metadata { return &parser.Metadata{ Status: status, StartedOn: startedOn, ScanToolName: scanToolName, + ScanToolUrl: scanToolUrl, } } @@ -60,7 +61,7 @@ func ExecutionDetailsToResourceScanResponseDto(respFromExecutionDetail *bean.Ima } vulnerabilityResponse := &parser.VulnerabilityResponse{} vulnerabilities := BuildVulnerabilitiesWrapperWithSummary(respFromExecutionDetail.Vulnerabilities) - imageVulResp := BuildImageVulnerabilityResponse(respFromExecutionDetail.Image, *vulnerabilities, BuildMetadata(respFromExecutionDetail.Status.String(), respFromExecutionDetail.ExecutionTime, respFromExecutionDetail.ScanToolName)) + imageVulResp := BuildImageVulnerabilityResponse(respFromExecutionDetail.Image, *vulnerabilities, BuildMetadata(respFromExecutionDetail.Status.String(), respFromExecutionDetail.ExecutionTime, respFromExecutionDetail.ScanToolName, respFromExecutionDetail.ScanToolUrl)) vulnerabilityResponse.Append(*imageVulResp) resp.ImageScan = &parser.ImageScanResponse{Vulnerability: vulnerabilityResponse} return resp diff --git a/pkg/policyGovernance/security/imageScanning/bean/bean.go b/pkg/policyGovernance/security/imageScanning/bean/bean.go index e989501f64..b250f8aff5 100644 --- a/pkg/policyGovernance/security/imageScanning/bean/bean.go +++ b/pkg/policyGovernance/security/imageScanning/bean/bean.go @@ -104,6 +104,7 @@ type ImageScanExecutionDetail struct { ObjectType string `json:"objectType,notnull"` ScanToolId int `json:"scanToolId,omitempty"` ScanToolName string `json:"scanToolName,omitempty"` + ScanToolUrl string `json:"scanToolUrl,omitempty"` Status repository.ScanExecutionProcessState `json:"status,omitempty"` } diff --git a/pkg/policyGovernance/security/imageScanning/helper/parser/parser.go b/pkg/policyGovernance/security/imageScanning/helper/parser/parser.go index 7fa2a040e6..27cb801d2c 100644 --- a/pkg/policyGovernance/security/imageScanning/helper/parser/parser.go +++ b/pkg/policyGovernance/security/imageScanning/helper/parser/parser.go @@ -1,5 +1,17 @@ /* * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package parser diff --git a/pkg/policyGovernance/security/imageScanning/helper/parser/types.go b/pkg/policyGovernance/security/imageScanning/helper/parser/types.go index 6bc583331e..8e7b0527e7 100644 --- a/pkg/policyGovernance/security/imageScanning/helper/parser/types.go +++ b/pkg/policyGovernance/security/imageScanning/helper/parser/types.go @@ -1,5 +1,17 @@ /* * Copyright (c) 2024. Devtron Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package parser @@ -51,6 +63,7 @@ type Metadata struct { Status string `json:"status"` StartedOn time.Time `json:"StartedOn"` ScanToolName string `json:"scanToolName"` + ScanToolUrl string `json:"scanToolUrl"` } type VulnerabilityResponse struct { diff --git a/pkg/policyGovernance/security/imageScanning/wire_imageScanning.go b/pkg/policyGovernance/security/imageScanning/wire_imageScanning.go index fa94fe0162..40796da0d1 100644 --- a/pkg/policyGovernance/security/imageScanning/wire_imageScanning.go +++ b/pkg/policyGovernance/security/imageScanning/wire_imageScanning.go @@ -3,6 +3,7 @@ package imageScanning import ( "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/read" "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" + repository2 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/repository" "github.com/google/wire" ) @@ -25,9 +26,6 @@ var ImageScanningWireSet = wire.NewSet( read.NewImageScanResultReadServiceImpl, wire.Bind(new(read.ImageScanResultReadService), new(*read.ImageScanResultReadServiceImpl)), - NewScanToolMetadataServiceImpl, - wire.Bind(new(ScanToolMetadataService), new(*ScanToolMetadataServiceImpl)), - repository.NewImageScanHistoryRepositoryImpl, wire.Bind(new(repository.ImageScanHistoryRepository), new(*repository.ImageScanHistoryRepositoryImpl)), repository.NewImageScanResultRepositoryImpl, @@ -38,8 +36,8 @@ var ImageScanningWireSet = wire.NewSet( wire.Bind(new(repository.CveStoreRepository), new(*repository.CveStoreRepositoryImpl)), repository.NewImageScanDeployInfoRepositoryImpl, wire.Bind(new(repository.ImageScanDeployInfoRepository), new(*repository.ImageScanDeployInfoRepositoryImpl)), - repository.NewScanToolMetadataRepositoryImpl, - wire.Bind(new(repository.ScanToolMetadataRepository), new(*repository.ScanToolMetadataRepositoryImpl)), + repository2.NewScanToolMetadataRepositoryImpl, + wire.Bind(new(repository2.ScanToolMetadataRepository), new(*repository2.ScanToolMetadataRepositoryImpl)), repository.NewPolicyRepositoryImpl, wire.Bind(new(repository.CvePolicyRepository), new(*repository.CvePolicyRepositoryImpl)), diff --git a/pkg/policyGovernance/security/imageScanning/ScanToolMetadataService.go b/pkg/policyGovernance/security/scanTool/ScanToolMetadataService.go similarity index 80% rename from pkg/policyGovernance/security/imageScanning/ScanToolMetadataService.go rename to pkg/policyGovernance/security/scanTool/ScanToolMetadataService.go index 8762a5f29e..4047831383 100644 --- a/pkg/policyGovernance/security/imageScanning/ScanToolMetadataService.go +++ b/pkg/policyGovernance/security/scanTool/ScanToolMetadataService.go @@ -1,7 +1,7 @@ -package imageScanning +package scanTool import ( - "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/repository" "github.com/go-pg/pg" "go.uber.org/zap" ) @@ -9,6 +9,8 @@ import ( type ScanToolMetadataService interface { MarkToolAsActive(toolName, version string, tx *pg.Tx) error MarkOtherToolsInActive(toolName string, tx *pg.Tx, version string) error + GetActiveTool() (*repository.ScanToolMetadata, error) + ScanToolMetadataService_ent } type ScanToolMetadataServiceImpl struct { @@ -30,3 +32,7 @@ func (impl *ScanToolMetadataServiceImpl) MarkToolAsActive(toolName, version stri func (impl *ScanToolMetadataServiceImpl) MarkOtherToolsInActive(toolName string, tx *pg.Tx, version string) error { return impl.scanToolMetadataRepository.MarkOtherToolsInActive(toolName, tx, version) } + +func (impl *ScanToolMetadataServiceImpl) GetActiveTool() (*repository.ScanToolMetadata, error) { + return impl.scanToolMetadataRepository.FindActiveTool() +} diff --git a/pkg/policyGovernance/security/scanTool/ScanToolMetadataService_ent.go b/pkg/policyGovernance/security/scanTool/ScanToolMetadataService_ent.go new file mode 100644 index 0000000000..2d762f54dc --- /dev/null +++ b/pkg/policyGovernance/security/scanTool/ScanToolMetadataService_ent.go @@ -0,0 +1,13 @@ +package scanTool + +import ( + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/bean" +) + +type ScanToolMetadataService_ent interface { + RegisterScanTools(registerScanToolDto *bean.RegisterScanToolsDto, userId int32) error +} + +func (impl *ScanToolMetadataServiceImpl) RegisterScanTools(registerScanToolDto *bean.RegisterScanToolsDto, userId int32) error { + return nil +} diff --git a/pkg/policyGovernance/security/scanTool/adaptor/adaptor.go b/pkg/policyGovernance/security/scanTool/adaptor/adaptor.go new file mode 100644 index 0000000000..08397cae0e --- /dev/null +++ b/pkg/policyGovernance/security/scanTool/adaptor/adaptor.go @@ -0,0 +1,30 @@ +package adaptor + +import ( + bean2 "github.com/devtron-labs/devtron/pkg/plugin/bean" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/bean" + "time" +) + +func GetPluginMetadataAndStepsDetail(scanToolPluginMetadataDto *bean.ScanToolPluginMetadataDto, scanToolUrl string, version string) *bean2.PluginParentMetadataDto { + pluginParentObj := &bean2.PluginParentMetadataDto{ + Name: scanToolPluginMetadataDto.Name, + PluginIdentifier: scanToolPluginMetadataDto.PluginIdentifier, + Description: scanToolPluginMetadataDto.Description, + Type: bean2.SHARED.ToString(), + Icon: scanToolUrl, + } + pluginMetadataDto := &bean2.PluginMetadataDto{ + Tags: []string{"Security"}, + PluginStage: "SCANNER", + PluginSteps: scanToolPluginMetadataDto.PluginSteps, + } + pluginVersionDetail := &bean2.PluginsVersionDetail{ + PluginMetadataDto: pluginMetadataDto, + Version: version, + IsLatest: true, + CreatedOn: time.Now(), + } + pluginParentObj.Versions = &bean2.PluginVersions{DetailedPluginVersionData: []*bean2.PluginsVersionDetail{pluginVersionDetail}} + return pluginParentObj +} diff --git a/pkg/policyGovernance/security/scanTool/bean/bean.go b/pkg/policyGovernance/security/scanTool/bean/bean.go new file mode 100644 index 0000000000..0ab1575f2d --- /dev/null +++ b/pkg/policyGovernance/security/scanTool/bean/bean.go @@ -0,0 +1,38 @@ +package bean + +import ( + bean2 "github.com/devtron-labs/devtron/pkg/plugin/bean" +) + +type RegisterScanToolsDto struct { + ScanToolMetadata *ScanToolsMetadataDto `json:"scanToolMetadata" validate:"dive,required"` + ScanToolPluginMetadata *ScanToolPluginMetadataDto `json:"scanToolPluginMetadata,omitempty" validate:"dive,required"` +} + +type ScanToolsMetadataDto struct { + ScanToolId int `json:"scanToolId,omitempty"` + Name string `json:"name,omitempty" validate:"required"` + Version string `json:"version,omitempty" validate:"required"` + ServerBaseUrl string `json:"serverBaseUrl,omitempty"` + ResultDescriptorTemplate string `json:"resultDescriptorTemplate,omitempty"` + ScanTarget ScanTargetType `json:"scanTarget,omitempty"` + ToolMetaData string `json:"toolMetadata,omitempty"` + ScanToolUrl string `json:"scanToolUrl,omitempty"` +} + +type ScanToolPluginMetadataDto struct { + Name string `json:"name" validate:"required,min=3,max=100"` + PluginIdentifier string `json:"pluginIdentifier" validate:"required,min=3,max=100,global-entity-name"` + Description string `json:"description" validate:"max=300"` + PluginSteps []*bean2.PluginStepsDto `json:"pluginSteps,omitempty"` +} + +const ( + DevtronImageScanningIntegratorPluginIdentifier = "devtron-image-scanning-integrator" +) + +type ScanTargetType string + +const ( + ScanTargetTypeImage ScanTargetType = "IMAGE" +) diff --git a/pkg/policyGovernance/security/imageScanning/repository/ScanToolMetaDataRepository.go b/pkg/policyGovernance/security/scanTool/repository/ScanToolMetaDataRepository.go similarity index 70% rename from pkg/policyGovernance/security/imageScanning/repository/ScanToolMetaDataRepository.go rename to pkg/policyGovernance/security/scanTool/repository/ScanToolMetaDataRepository.go index e4520bea61..dc9e882497 100644 --- a/pkg/policyGovernance/security/imageScanning/repository/ScanToolMetaDataRepository.go +++ b/pkg/policyGovernance/security/scanTool/repository/ScanToolMetaDataRepository.go @@ -17,39 +17,41 @@ package repository import ( + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/bean" "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" "go.uber.org/zap" ) -type ScanTargetType string - type ScanToolMetadata struct { - tableName struct{} `sql:"scan_tool_metadata" pg:",discard_unknown_columns"` - Id int `sql:"id,pk"` - Name string `sql:"name"` - Version string `sql:"version"` - ServerBaseUrl string `sql:"server_base_url"` - ResultDescriptorTemplate string `sql:"result_descriptor_template"` - ScanTarget ScanTargetType `sql:"scan_target"` - Active bool `sql:"active,notnull"` - Deleted bool `sql:"deleted,notnull"` - ToolMetaData string `sql:"tool_metadata"` + tableName struct{} `sql:"scan_tool_metadata" pg:",discard_unknown_columns"` + Id int `sql:"id,pk"` + Name string `sql:"name"` + Version string `sql:"version"` + ServerBaseUrl string `sql:"server_base_url"` + ResultDescriptorTemplate string `sql:"result_descriptor_template"` + ScanTarget bean.ScanTargetType `sql:"scan_target"` + Active bool `sql:"active,notnull"` + Deleted bool `sql:"deleted,notnull"` + ToolMetaData string `sql:"tool_metadata"` + PluginId int `sql:"plugin_id"` + IsPreset bool `sql:"is_preset,notnull"` + Url string `sql:"url"` sql.AuditLog } type ScanToolMetadataRepository interface { - FindActiveToolByScanTarget(scanTarget ScanTargetType) (*ScanToolMetadata, error) + FindActiveToolByScanTarget(scanTarget bean.ScanTargetType) (*ScanToolMetadata, error) FindByNameAndVersion(name, version string) (*ScanToolMetadata, error) FindActiveById(id int) (*ScanToolMetadata, error) - Save(model *ScanToolMetadata) (*ScanToolMetadata, error) + Save(tx *pg.Tx, model *ScanToolMetadata) (*ScanToolMetadata, error) Update(model *ScanToolMetadata) (*ScanToolMetadata, error) MarkToolDeletedById(id int) error FindAllActiveTools() ([]*ScanToolMetadata, error) MarkToolAsActive(toolName, version string, tx *pg.Tx) error MarkOtherToolsInActive(toolName string, tx *pg.Tx, version string) error FindActiveTool() (*ScanToolMetadata, error) - FindNameById(id int) (string, error) + FindNameAndUrlById(id int) (string, string, error) } type ScanToolMetadataRepositoryImpl struct { @@ -65,7 +67,7 @@ func NewScanToolMetadataRepositoryImpl(dbConnection *pg.DB, } } -func (repo *ScanToolMetadataRepositoryImpl) FindActiveToolByScanTarget(scanTargetType ScanTargetType) (*ScanToolMetadata, error) { +func (repo *ScanToolMetadataRepositoryImpl) FindActiveToolByScanTarget(scanTargetType bean.ScanTargetType) (*ScanToolMetadata, error) { var model ScanToolMetadata err := repo.dbConnection.Model(&model).Where("active = ?", true). Where("scan_target = ?", scanTargetType). @@ -101,12 +103,21 @@ func (repo *ScanToolMetadataRepositoryImpl) FindActiveById(id int) (*ScanToolMet return model, nil } -func (repo *ScanToolMetadataRepositoryImpl) Save(model *ScanToolMetadata) (*ScanToolMetadata, error) { - err := repo.dbConnection.Insert(model) - if err != nil { - repo.logger.Errorw("error in saving scan tool metadata", "err", err, "model", model) - return nil, err +func (repo *ScanToolMetadataRepositoryImpl) Save(tx *pg.Tx, model *ScanToolMetadata) (*ScanToolMetadata, error) { + if tx != nil { + err := tx.Insert(model) + if err != nil { + repo.logger.Errorw("error in saving scan tool metadata using transaction", "model", model, "err", err) + return nil, err + } + } else { + err := repo.dbConnection.Insert(model) + if err != nil { + repo.logger.Errorw("error in saving scan tool metadata", "model", model, "err", err) + return nil, err + } } + return model, nil } @@ -145,7 +156,7 @@ func (repo *ScanToolMetadataRepositoryImpl) MarkToolAsActive(toolName, version s _, err := tx.Model(model).Set("active = ?", true).Where("name = ?", toolName).Where("version = ?", version).Update() if err != nil { - repo.logger.Errorw("error in marking tool active for scan target", "err", err) + repo.logger.Errorw("error in marking tool active for scan target", "toolName", toolName, "err", err) return err } return nil @@ -155,14 +166,14 @@ func (repo *ScanToolMetadataRepositoryImpl) MarkOtherToolsInActive(toolName stri _, err := tx.Model(model).Set("active = ?", false).Where("name != ?", toolName).Where("version != ?", version).Update() if err != nil { - repo.logger.Errorw("error in marking tool active for scan target", "err", err) + repo.logger.Errorw("error in marking tool active for scan target", "toolName", toolName, "err", err) return err } return nil } func (repo *ScanToolMetadataRepositoryImpl) FindActiveTool() (*ScanToolMetadata, error) { - var model *ScanToolMetadata - err := repo.dbConnection.Model(&model).Where("active = ?", true). + model := &ScanToolMetadata{} + err := repo.dbConnection.Model(model).Where("active = ?", true). Where("deleted = ?", false).Select() if err != nil { repo.logger.Errorw("error in getting active tool for scan target", "err", err) @@ -172,12 +183,12 @@ func (repo *ScanToolMetadataRepositoryImpl) FindActiveTool() (*ScanToolMetadata, } -func (repo *ScanToolMetadataRepositoryImpl) FindNameById(id int) (string, error) { +func (repo *ScanToolMetadataRepositoryImpl) FindNameAndUrlById(id int) (string, string, error) { model := &ScanToolMetadata{} - err := repo.dbConnection.Model(model).Column("name").Where("id = ?", id).Select() + err := repo.dbConnection.Model(model).Column("name", "url").Where("id = ?", id).Select() if err != nil { repo.logger.Errorw("error in getting tool name by id", "err", err, "id", id) - return "", err + return "", "", err } - return model.Name, nil + return model.Name, model.Url, nil } diff --git a/pkg/policyGovernance/security/scanTool/wire_scanTool.go b/pkg/policyGovernance/security/scanTool/wire_scanTool.go new file mode 100644 index 0000000000..6889db79c0 --- /dev/null +++ b/pkg/policyGovernance/security/scanTool/wire_scanTool.go @@ -0,0 +1,8 @@ +package scanTool + +import "github.com/google/wire" + +var ScanToolWireSet = wire.NewSet( + NewScanToolMetadataServiceImpl, + wire.Bind(new(ScanToolMetadataService), new(*ScanToolMetadataServiceImpl)), +) diff --git a/pkg/policyGovernance/wire_policyGovernance.go b/pkg/policyGovernance/wire_policyGovernance.go index a87920b4dd..06dc56b168 100644 --- a/pkg/policyGovernance/wire_policyGovernance.go +++ b/pkg/policyGovernance/wire_policyGovernance.go @@ -2,9 +2,11 @@ package policyGovernance import ( "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool" "github.com/google/wire" ) var PolicyGovernanceWireSet = wire.NewSet( imageScanning.ImageScanningWireSet, + scanTool.ScanToolWireSet, ) diff --git a/pkg/resourceQualifiers/QualifierMappingService.go b/pkg/resourceQualifiers/QualifierMappingService.go index 6cbf46ad04..98af688320 100644 --- a/pkg/resourceQualifiers/QualifierMappingService.go +++ b/pkg/resourceQualifiers/QualifierMappingService.go @@ -285,6 +285,7 @@ func (impl *QualifierMappingServiceImpl) GetResourceMappingsForSelections(resour return impl.processMappings(resourceType, mappings, qualifierSelector, getCompositeStringsAppEnvSelection(selectionIdentifiers)) } + func (impl *QualifierMappingServiceImpl) GetResourceMappingsForResources(resourceType ResourceType, resourceIds []int, qualifierSelector QualifierSelector) ([]ResourceQualifierMappings, error) { mappings, err := impl.qualifierMappingRepository.GetMappingsByResourceTypeAndIdsAndQualifierId(resourceType, resourceIds, int(qualifierSelector.toQualifier())) if err != nil { diff --git a/pkg/workflow/dag/WorkflowDagExecutor.go b/pkg/workflow/dag/WorkflowDagExecutor.go index c25c087cfa..cfd6236c34 100644 --- a/pkg/workflow/dag/WorkflowDagExecutor.go +++ b/pkg/workflow/dag/WorkflowDagExecutor.go @@ -23,6 +23,7 @@ import ( "fmt" "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/devtron-labs/common-lib/async" + "github.com/devtron-labs/common-lib/utils" "github.com/devtron-labs/common-lib/utils/workFlow" bean6 "github.com/devtron-labs/devtron/api/helm-app/bean" client2 "github.com/devtron-labs/devtron/api/helm-app/service" @@ -869,6 +870,7 @@ func (impl *WorkflowDagExecutorImpl) HandleCiSuccessEvent(triggerContext trigger IsArtifactUploaded: request.IsArtifactUploaded, // for backward compatibility ScanEnabled: buildArtifact.ScanEnabled, Scanned: false, + TargetPlatforms: utils.ConvertTargetPlatformListToString(request.TargetPlatforms), AuditLog: sql.AuditLog{CreatedBy: request.UserId, UpdatedBy: request.UserId, CreatedOn: time.Now(), UpdatedOn: time.Now()}, } if buildArtifact.ScanEnabled { diff --git a/pkg/workflow/dag/adaptor/adaptor.go b/pkg/workflow/dag/adaptor/adaptor.go index 0ed23888f1..8b0e285a17 100644 --- a/pkg/workflow/dag/adaptor/adaptor.go +++ b/pkg/workflow/dag/adaptor/adaptor.go @@ -1,6 +1,7 @@ package adaptor import ( + "github.com/devtron-labs/common-lib/utils" "github.com/devtron-labs/devtron/internal/sql/repository" "github.com/devtron-labs/devtron/pkg/sql" bean2 "github.com/devtron-labs/devtron/pkg/workflow/dag/bean" @@ -18,6 +19,7 @@ func GetBuildArtifact(request *bean2.CiArtifactWebhookRequest, ciPipelineId int, ScanEnabled: request.IsScanEnabled, IsArtifactUploaded: request.IsArtifactUploaded, // for backward compatibility Scanned: false, + TargetPlatforms: utils.ConvertTargetPlatformListToString(request.TargetPlatforms), AuditLog: sql.AuditLog{CreatedBy: request.UserId, UpdatedBy: request.UserId, CreatedOn: createdOn, UpdatedOn: updatedOn}, } } diff --git a/pkg/workflow/dag/bean/bean.go b/pkg/workflow/dag/bean/bean.go index 92b6144ff7..5601417232 100644 --- a/pkg/workflow/dag/bean/bean.go +++ b/pkg/workflow/dag/bean/bean.go @@ -35,6 +35,7 @@ type CiArtifactWebhookRequest struct { PluginRegistryArtifactDetails map[string][]string `json:"PluginRegistryArtifactDetails"` //map of registry and array of images generated by Copy container image plugin PluginArtifactStage string `json:"pluginArtifactStage"` // at which stage of CI artifact was generated by plugin ("pre_ci/post_ci") IsScanEnabled bool `json:"isScanEnabled"` + TargetPlatforms []string `json:"targetPlatforms"` } const ( diff --git a/pkg/workflow/status/WorkflowStatusService.go b/pkg/workflow/status/WorkflowStatusService.go index a8703d16d6..e889a9c1a2 100644 --- a/pkg/workflow/status/WorkflowStatusService.go +++ b/pkg/workflow/status/WorkflowStatusService.go @@ -19,11 +19,9 @@ package status import ( "context" "fmt" - application2 "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" bean2 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/api/helm-app/service/bean" "github.com/devtron-labs/devtron/client/argocdServer" - "github.com/devtron-labs/devtron/client/argocdServer/application" appRepository "github.com/devtron-labs/devtron/internal/sql/repository/app" "github.com/devtron-labs/devtron/internal/sql/repository/chartConfig" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" @@ -87,9 +85,7 @@ type WorkflowStatusServiceImpl struct { pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository pipelineRepository pipelineConfig.PipelineRepository appListingService app.AppListingService - - application application.ServiceClient - deploymentConfigService common2.DeploymentConfigService + deploymentConfigService common2.DeploymentConfigService } func NewWorkflowStatusServiceImpl(logger *zap.SugaredLogger, @@ -109,7 +105,6 @@ func NewWorkflowStatusServiceImpl(logger *zap.SugaredLogger, installedAppReadService installedAppReader.InstalledAppReadService, pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository, pipelineRepository pipelineConfig.PipelineRepository, - application application.ServiceClient, appListingService app.AppListingService, deploymentConfigService common2.DeploymentConfigService, ) (*WorkflowStatusServiceImpl, error) { @@ -133,7 +128,6 @@ func NewWorkflowStatusServiceImpl(logger *zap.SugaredLogger, installedAppReadService: installedAppReadService, pipelineStatusTimelineRepository: pipelineStatusTimelineRepository, pipelineRepository: pipelineRepository, - application: application, appListingService: appListingService, deploymentConfigService: deploymentConfigService, } @@ -236,10 +230,7 @@ func (impl *WorkflowStatusServiceImpl) UpdatePipelineTimelineAndStatusByLiveAppl } // this should only be called when we have git-ops configured // try fetching status from argo cd - query := &application2.ApplicationQuery{ - Name: &pipeline.DeploymentAppName, - } - app, err := impl.application.Get(context.Background(), query) + app, err := impl.argocdClientWrapperService.GetArgoAppByName(context.Background(), pipeline.DeploymentAppName) if err != nil { impl.logger.Errorw("error in getting acd application", "err", err, "argoAppName", pipeline) // updating cdWfr status @@ -334,10 +325,8 @@ func (impl *WorkflowStatusServiceImpl) UpdatePipelineTimelineAndStatusByLiveAppl // this should only be called when we have git-ops configured // try fetching status from argo cd - query := &application2.ApplicationQuery{ - Name: &acdAppName, - } - app, err := impl.application.Get(context.Background(), query) + + app, err := impl.argocdClientWrapperService.GetArgoAppByName(context.Background(), acdAppName) if err != nil { impl.logger.Errorw("error in getting acd application", "err", err, "installedApp", installedApp) // updating cdWfr status diff --git a/scripts/sql/31602800_build_infra_cm_cs.down.sql b/scripts/sql/31602800_build_infra_cm_cs.down.sql new file mode 100644 index 0000000000..e543a08da3 --- /dev/null +++ b/scripts/sql/31602800_build_infra_cm_cs.down.sql @@ -0,0 +1,13 @@ +BEGIN; + +-- Drop Table: infra_config_trigger_history +DROP TABLE IF EXISTS "public"."infra_config_trigger_history"; + +-- Drop Sequence for infra_config_trigger_history +DROP SEQUENCE IF EXISTS "public"."id_seq_infra_config_trigger_history"; + +--hard deleting the entries +DELETE FROM "public"."infra_profile_configuration" +WHERE key = 8 or key =9; + +END; \ No newline at end of file diff --git a/scripts/sql/31602800_build_infra_cm_cs.up.sql b/scripts/sql/31602800_build_infra_cm_cs.up.sql new file mode 100644 index 0000000000..2c6e377bf7 --- /dev/null +++ b/scripts/sql/31602800_build_infra_cm_cs.up.sql @@ -0,0 +1,22 @@ +BEGIN; + +-- Create Sequence for infra_config_trigger_history +CREATE SEQUENCE IF NOT EXISTS "public"."id_seq_infra_config_trigger_history"; + +-- Table Definition: infra_config_trigger_history +CREATE TABLE IF NOT EXISTS "public"."infra_config_trigger_history" ( + "id" int NOT NULL DEFAULT nextval('id_seq_infra_config_trigger_history'::regclass), + "key" int NOT NULL, + "value_string" text, + "platform" varchar(50) NOT NULL, + "workflow_id" int NOT NULL, + "workflow_type" varchar(255) NOT NULL, + "created_on" timestamptz NOT NULL, + "created_by" int4 NOT NULL, + "updated_on" timestamptz NOT NULL, + "updated_by" int4 NOT NULL, + PRIMARY KEY ("id"), + UNIQUE ("workflow_id", "workflow_type", "key", "platform") +); + +END; \ No newline at end of file diff --git a/scripts/sql/31702800_artifact_target_platform.down.sql b/scripts/sql/31702800_artifact_target_platform.down.sql new file mode 100644 index 0000000000..f5a7cf9ca2 --- /dev/null +++ b/scripts/sql/31702800_artifact_target_platform.down.sql @@ -0,0 +1 @@ +ALTER TABLE public.ci_artifact DROP COLUMN IF EXISTS target_platforms; \ No newline at end of file diff --git a/scripts/sql/31702800_artifact_target_platform.up.sql b/scripts/sql/31702800_artifact_target_platform.up.sql new file mode 100644 index 0000000000..cfc6a65eb4 --- /dev/null +++ b/scripts/sql/31702800_artifact_target_platform.up.sql @@ -0,0 +1 @@ +ALTER TABLE public.ci_artifact ADD COLUMN IF NOT EXISTS target_platforms varchar(200) NULL; diff --git a/scripts/sql/31802800_aws_inspector.down.sql b/scripts/sql/31802800_aws_inspector.down.sql new file mode 100644 index 0000000000..e23a7f76b4 --- /dev/null +++ b/scripts/sql/31802800_aws_inspector.down.sql @@ -0,0 +1,12 @@ +-- Begin Transaction +BEGIN; +--------------------------------------- +ALTER TABLE public.plugin_parent_metadata DROP COLUMN IF EXISTS is_exposed; +ALTER TABLE public.plugin_metadata DROP COLUMN IF EXISTS is_exposed ; +ALTER TABLE public.scan_tool_metadata DROP COLUMN IF EXISTS is_preset ; +ALTER TABLE public.scan_tool_metadata DROP COLUMN IF EXISTS plugin_id; +ALTER TABLE public.scan_tool_metadata DROP CONSTRAINT IF EXISTS scan_tool_metadata_name_version_unique; +ALTER TABLE public.scan_tool_metadata DROP COLUMN IF EXISTS url; + +-- --------------------------------------------------- +COMMIT; \ No newline at end of file diff --git a/scripts/sql/31802800_aws_inspector.up.sql b/scripts/sql/31802800_aws_inspector.up.sql new file mode 100644 index 0000000000..cf7619c7a3 --- /dev/null +++ b/scripts/sql/31802800_aws_inspector.up.sql @@ -0,0 +1,22 @@ +-- Begin Transaction +BEGIN; +-- Adding Exposed on plugin metadata and plugin parent metadata +ALTER TABLE public.plugin_parent_metadata ADD COLUMN IF NOT EXISTS is_exposed bool NOT NULL DEFAULT true; +ALTER TABLE public.plugin_metadata ADD COLUMN IF NOT EXISTS is_exposed bool NOT NULL DEFAULT true; + +-- Preset flag is added to scan_tool_metadata to define tool added by user or devtron system +ALTER TABLE public.scan_tool_metadata ADD COLUMN IF NOT EXISTS is_preset bool NOT NULL DEFAULT true; +-- Plugin Id is added to scan_tool_metadata as foreign key +ALTER TABLE public.scan_tool_metadata ADD COLUMN IF NOT EXISTS plugin_id int; +ALTER TABLE "public"."scan_tool_metadata" ADD FOREIGN KEY ("plugin_id") REFERENCES "public"."plugin_metadata" ("id"); +ALTER TABLE public.scan_tool_metadata ADD CONSTRAINT scan_tool_metadata_name_version_unique UNIQUE ("name", "version"); + +ALTER TABLE public.scan_tool_metadata ADD COLUMN IF NOT EXISTS url varchar(100); + +UPDATE public.scan_tool_metadata SET url='https://cdn.devtron.ai/images/ic-clair.webp' WHERE name='CLAIR'; +UPDATE public.scan_tool_metadata SET url='https://cdn.devtron.ai/images/ic-trivy.webp' WHERE name='TRIVY'; + +-- --------------------------------------------------- +-- Commit Transaction +-- --------------------------------------------------- +COMMIT; diff --git a/util/GlobalConfig.go b/util/GlobalConfig.go index 879c34094e..a30ee0c884 100644 --- a/util/GlobalConfig.go +++ b/util/GlobalConfig.go @@ -26,12 +26,14 @@ type EnvironmentVariables struct { DeploymentServiceTypeConfig *DeploymentServiceTypeConfig TerminalEnvVariables *TerminalEnvVariables GlobalClusterConfig *GlobalClusterConfig + InternalEnvVariables *InternalEnvVariables } type DeploymentServiceTypeConfig struct { ExternallyManagedDeploymentType bool `env:"IS_INTERNAL_USE" envDefault:"false"` HelmInstallASyncMode bool `env:"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS" envDefault:"false"` UseDeploymentConfigData bool `env:"USE_DEPLOYMENT_CONFIG_DATA" envDefault:"false"` + ShouldCheckNamespaceOnClone bool `env:"SHOULD_CHECK_NAMESPACE_ON_CLONE" envDefault:"false" description:"should we check if namespace exists or not while cloning app" deprecated:"false"` } type GlobalEnvVariables struct { @@ -57,6 +59,28 @@ type TerminalEnvVariables struct { RestrictTerminalAccessForNonSuperUser bool `env:"RESTRICT_TERMINAL_ACCESS_FOR_NON_SUPER_USER" envDefault:"false"` } +type InternalEnvVariables struct { + // GoRuntimeEnv specifies the runtime environment of the application, + // - enum: + // "development" + // "production" + // - default: "production" + // - use cases: test cases to set the runtime environment + GoRuntimeEnv string `env:"GO_RUNTIME_ENV" envDefault:"production"` +} + +func (i *InternalEnvVariables) IsDevelopmentEnv() bool { + if i == nil { + return false + } + return i.GoRuntimeEnv == "development" +} + +func (i *InternalEnvVariables) SetDevelopmentEnv() *InternalEnvVariables { + i.GoRuntimeEnv = "development" + return i +} + func GetEnvironmentVariables() (*EnvironmentVariables, error) { cfg := &EnvironmentVariables{ GlobalEnvVariables: &GlobalEnvVariables{}, @@ -64,6 +88,7 @@ func GetEnvironmentVariables() (*EnvironmentVariables, error) { DeploymentServiceTypeConfig: &DeploymentServiceTypeConfig{}, TerminalEnvVariables: &TerminalEnvVariables{}, GlobalClusterConfig: &GlobalClusterConfig{}, + InternalEnvVariables: &InternalEnvVariables{}, } err := env.Parse(cfg) if err != nil { diff --git a/util/sliceUtil/SliceUtil.go b/util/sliceUtil/SliceUtil.go index accbe318c1..8c816d4164 100644 --- a/util/sliceUtil/SliceUtil.go +++ b/util/sliceUtil/SliceUtil.go @@ -168,3 +168,28 @@ func GetMapValuesPtr[T any](valueMap map[string]*T) []*T { } return values } + +// Filter appends to d each element e of s for which keep(e) returns true. +// It returns the modified d. d may be s[:0], in which case the kept +// elements will be stored in the same slice. +// if the slices overlap in some other way, the results are unspecified. +// To create a new slice with the filtered results, pass nil for d. +func Filter[T any](d, s []T, keep func(T) bool) []T { + for _, n := range s { + if keep(n) { + d = append(d, n) + } + } + return d +} + +// Find returns the index of the first element in s that satisfies the predicate func find. +// If no element satisfies the predicate, the function returns -1 and false. +func Find[T any](s []T, find func(T) bool) (int, bool) { + for i := range s { + if find(s[i]) { + return i, true + } + } + return -1, false +} diff --git a/vendor/github.com/devtron-labs/common-lib/imageScan/bean/bean.go b/vendor/github.com/devtron-labs/common-lib/imageScan/bean/bean.go index b18d694eac..79decb1db2 100644 --- a/vendor/github.com/devtron-labs/common-lib/imageScan/bean/bean.go +++ b/vendor/github.com/devtron-labs/common-lib/imageScan/bean/bean.go @@ -62,3 +62,22 @@ func (r *ImageScanEvent) IsImageFromManifest() bool { func (r *ImageScanEvent) IsBuiltImage() bool { return r.SourceType == constants.SourceTypeImage && r.SourceSubType == constants.SourceSubTypeCi } + +type ScanResultPayload struct { + ImageScanEvent *ImageScanEvent + ScanToolId int `json:"scanToolId"` + SourceScanningResult string `json:"sourceScanningResult"` + Sbom string `json:"sbom"` + ImageScanOutput []*ImageScanOutputObject `json:"imageScanOutput"` +} + +type ImageScanOutputObject struct { + TargetName string `json:"targetName"` + Class string `json:"class"` + Type string `json:"type"` + Name string `json:"name"` + Package string `json:"package"` + PackageVersion string `json:"packageVersion"` + FixedInVersion string `json:"fixedInVersion"` + Severity string `json:"severity"` +} diff --git a/vendor/github.com/devtron-labs/common-lib/imageScan/bean/executionBean.go b/vendor/github.com/devtron-labs/common-lib/imageScan/bean/executionBean.go new file mode 100644 index 0000000000..d1313aba58 --- /dev/null +++ b/vendor/github.com/devtron-labs/common-lib/imageScan/bean/executionBean.go @@ -0,0 +1,16 @@ +package bean + +type ScanExecutionMedium string + +const ( + InHouse ScanExecutionMedium = "in-house" // this contains all methods of hitting image scanner directly via rest or rpc + External ScanExecutionMedium = "external" // if a scan tool is registered via api and execution is via plugin steps +) + +func (e ScanExecutionMedium) IsScanExecutionMediumInHouse() bool { + return e == InHouse +} + +func (e ScanExecutionMedium) IsScanMediumExternal() bool { + return e == External +} diff --git a/vendor/github.com/devtron-labs/common-lib/utils/CommonUtils.go b/vendor/github.com/devtron-labs/common-lib/utils/CommonUtils.go index 4f92471ed3..ad3cbbda0d 100644 --- a/vendor/github.com/devtron-labs/common-lib/utils/CommonUtils.go +++ b/vendor/github.com/devtron-labs/common-lib/utils/CommonUtils.go @@ -36,9 +36,13 @@ import ( var chars = []rune("abcdefghijklmnopqrstuvwxyz0123456789") const ( - DOCKER_REGISTRY_TYPE_DOCKERHUB = "docker-hub" - DEVTRON_SELF_POD_UID = "DEVTRON_SELF_POD_UID" - DEVTRON_SELF_POD_NAME = "DEVTRON_SELF_POD_NAME" + DOCKER_REGISTRY_TYPE_DOCKERHUB = "docker-hub" + DEVTRON_SELF_POD_UID = "DEVTRON_SELF_POD_UID" + DEVTRON_SELF_POD_NAME = "DEVTRON_SELF_POD_NAME" + DEVTRON_SELF_DOWNWARD_API_VOLUME = "devtron-pod-info" + DEVTRON_SELF_DOWNWARD_API_VOLUME_PATH = "/etc/devtron-pod-info" + POD_LABELS = "labels" + POD_ANNOTATIONS = "annotations" ) // Generates random string @@ -151,3 +155,22 @@ var PgQueryDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "pg_query_duration_seconds", Help: "Duration of PG queries", }, []string{"status", "serviceName"}) + +func ConvertTargetPlatformStringToObject(targetPlatformString string) []*bean.TargetPlatform { + targetPlatforms := ConvertTargetPlatformStringToList(targetPlatformString) + targetPlatformObject := []*bean.TargetPlatform{} + for _, targetPlatform := range targetPlatforms { + if len(targetPlatform) > 0 { + targetPlatformObject = append(targetPlatformObject, &bean.TargetPlatform{Name: targetPlatform}) + } + } + return targetPlatformObject +} + +func ConvertTargetPlatformStringToList(targetPlatform string) []string { + return strings.Split(targetPlatform, ",") +} + +func ConvertTargetPlatformListToString(targetPlatforms []string) string { + return strings.Join(targetPlatforms, ",") +} diff --git a/vendor/github.com/devtron-labs/common-lib/utils/FileUtil.go b/vendor/github.com/devtron-labs/common-lib/utils/FileUtil.go index a26977c6ba..61d8c5fff9 100644 --- a/vendor/github.com/devtron-labs/common-lib/utils/FileUtil.go +++ b/vendor/github.com/devtron-labs/common-lib/utils/FileUtil.go @@ -1,6 +1,8 @@ package utils import ( + "errors" + "fmt" "io/ioutil" "os" "path" @@ -34,3 +36,39 @@ func DeleteAFileIfExists(path string) error { } return nil } + +const ( + PermissionMode = 0644 +) + +func CreateDirectory(path string) error { + err := os.MkdirAll(path, PermissionMode) + if err != nil { + fmt.Println("error in creating directory", "err", err) + return err + } + return nil +} + +func CheckFileExists(filename string) (bool, error) { + if _, err := os.Stat(filename); err == nil { + // exists + return true, nil + + } else if errors.Is(err, os.ErrNotExist) { + // not exists + return false, nil + } else { + // Some other error + return false, err + } +} + +func WriteToFile(file string, fileName string) error { + err := os.WriteFile(fileName, []byte(file), PermissionMode) + if err != nil { + fmt.Println("error in writing results to json file", "err", err) + return err + } + return nil +} diff --git a/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go b/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go index 56d485090e..50b122e495 100644 --- a/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go +++ b/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go @@ -84,3 +84,7 @@ type PgQueryEvent struct { Error error Query string } + +type TargetPlatform struct { + Name string `json:"name"` +} diff --git a/vendor/github.com/devtron-labs/common-lib/utils/registry/bean.go b/vendor/github.com/devtron-labs/common-lib/utils/registry/bean.go index 457453268f..d6796fe3bd 100644 --- a/vendor/github.com/devtron-labs/common-lib/utils/registry/bean.go +++ b/vendor/github.com/devtron-labs/common-lib/utils/registry/bean.go @@ -1,18 +1,28 @@ package registry -type registry string +type Registry string -func (r registry) String() string { +func (r Registry) String() string { return string(r) } const ( - DOCKER_REGISTRY_TYPE_ECR registry = "ecr" - DOCKER_REGISTRY_TYPE_ACR registry = "acr" - DOCKER_REGISTRY_TYPE_DOCKERHUB registry = "docker-hub" - DOCKER_REGISTRY_TYPE_OTHER registry = "other" - REGISTRY_TYPE_ARTIFACT_REGISTRY registry = "artifact-registry" - REGISTRY_TYPE_GCR registry = "gcr" + DOCKER_REGISTRY_TYPE_ECR Registry = "ecr" + DOCKER_REGISTRY_TYPE_ACR Registry = "acr" + DOCKER_REGISTRY_TYPE_DOCKERHUB Registry = "docker-hub" + DOCKER_REGISTRY_TYPE_OTHER Registry = "other" + REGISTRY_TYPE_ARTIFACT_REGISTRY Registry = "artifact-registry" + REGISTRY_TYPE_GCR Registry = "gcr" ) const JSON_KEY_USERNAME = "_json_key" + +type RegistryCredential struct { + RegistryType Registry `json:"registryType"` + RegistryURL string `json:"registryURL"` + Username string `json:"username"` + Password string `json:"password"` + AWSAccessKeyId string `json:"awsAccessKeyId,omitempty"` + AWSSecretAccessKey string `json:"awsSecretAccessKey,omitempty"` + AWSRegion string `json:"awsRegion,omitempty"` +} diff --git a/vendor/github.com/devtron-labs/common-lib/utils/registry/extractCredentials.go b/vendor/github.com/devtron-labs/common-lib/utils/registry/extractCredentials.go new file mode 100644 index 0000000000..b0017670f4 --- /dev/null +++ b/vendor/github.com/devtron-labs/common-lib/utils/registry/extractCredentials.go @@ -0,0 +1,72 @@ +package registry + +import ( + "encoding/base64" + "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ecr" + "strings" +) + +func ExtractCredentialsForRegistry(registryCredential *RegistryCredential) (string, string, error) { + username := registryCredential.Username + pwd := registryCredential.Password + if (registryCredential.RegistryType == REGISTRY_TYPE_GCR || registryCredential.RegistryType == REGISTRY_TYPE_ARTIFACT_REGISTRY) && username == JSON_KEY_USERNAME { + if strings.HasPrefix(pwd, "'") { + pwd = pwd[1:] + } + if strings.HasSuffix(pwd, "'") { + pwd = pwd[:len(pwd)-1] + } + } + if registryCredential.RegistryType == DOCKER_REGISTRY_TYPE_ECR { + accessKey, secretKey := registryCredential.AWSAccessKeyId, registryCredential.AWSSecretAccessKey + var creds *credentials.Credentials + + if len(registryCredential.AWSAccessKeyId) == 0 || len(registryCredential.AWSSecretAccessKey) == 0 { + sess, err := session.NewSession(&aws.Config{ + Region: ®istryCredential.AWSRegion, + }) + if err != nil { + fmt.Printf("Error in creating AWS client", "err", err) + return "", "", err + } + creds = ec2rolecreds.NewCredentials(sess) + } else { + creds = credentials.NewStaticCredentials(accessKey, secretKey, "") + } + sess, err := session.NewSession(&aws.Config{ + Region: ®istryCredential.AWSRegion, + Credentials: creds, + }) + if err != nil { + fmt.Println("Error in creating AWS client session", "err", err) + return "", "", err + } + svc := ecr.New(sess) + input := &ecr.GetAuthorizationTokenInput{} + authData, err := svc.GetAuthorizationToken(input) + if err != nil { + fmt.Println("Error fetching authData", "err", err) + return "", "", err + } + // decode token + token := authData.AuthorizationData[0].AuthorizationToken + decodedToken, err := base64.StdEncoding.DecodeString(*token) + if err != nil { + fmt.Println("Error in decoding auth token", "err", err) + return "", "", err + } + credsSlice := strings.Split(string(decodedToken), ":") + if len(credsSlice) < 2 { + fmt.Println("Error in decoding auth token", "err", err) + return "", "", fmt.Errorf("error in decoding auth token for docker Registry") + } + username = credsSlice[0] + pwd = credsSlice[1] + } + return username, pwd, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index cad591f14d..aa07298980 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -336,7 +336,7 @@ github.com/davecgh/go-spew/spew # github.com/deckarep/golang-set v1.8.0 ## explicit; go 1.17 github.com/deckarep/golang-set -# github.com/devtron-labs/authenticator v0.4.35-0.20240809073103-6e11da8083f8 => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250116083207-90a2b2acbc2a +# github.com/devtron-labs/authenticator v0.4.35-0.20240809073103-6e11da8083f8 => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2 ## explicit; go 1.21 github.com/devtron-labs/authenticator/apiToken github.com/devtron-labs/authenticator/client @@ -344,7 +344,7 @@ github.com/devtron-labs/authenticator/jwt github.com/devtron-labs/authenticator/middleware github.com/devtron-labs/authenticator/oidc github.com/devtron-labs/authenticator/password -# github.com/devtron-labs/common-lib v0.18.1-0.20241001061923-eda545dc839e => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250122120743-f9dc0038c36a +# github.com/devtron-labs/common-lib v0.18.1-0.20241001061923-eda545dc839e => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2 ## explicit; go 1.21 github.com/devtron-labs/common-lib/async github.com/devtron-labs/common-lib/blob-storage @@ -2215,8 +2215,8 @@ xorm.io/xorm/log xorm.io/xorm/names xorm.io/xorm/schemas xorm.io/xorm/tags -# github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250116083207-90a2b2acbc2a -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250122120743-f9dc0038c36a +# github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2 # github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 # github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.5.5 # k8s.io/api => k8s.io/api v0.29.7 diff --git a/wire_gen.go b/wire_gen.go index 3726c97ffb..b59e017b53 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -73,12 +73,14 @@ import ( "github.com/devtron-labs/devtron/cel" "github.com/devtron-labs/devtron/client/argocdServer" "github.com/devtron-labs/devtron/client/argocdServer/application" + "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/client/argocdServer/certificate" - "github.com/devtron-labs/devtron/client/argocdServer/cluster" + cluster2 "github.com/devtron-labs/devtron/client/argocdServer/cluster" + config3 "github.com/devtron-labs/devtron/client/argocdServer/config" "github.com/devtron-labs/devtron/client/argocdServer/connection" "github.com/devtron-labs/devtron/client/argocdServer/repoCredsK8sClient" - repository26 "github.com/devtron-labs/devtron/client/argocdServer/repocreds" - repository21 "github.com/devtron-labs/devtron/client/argocdServer/repository" + repository7 "github.com/devtron-labs/devtron/client/argocdServer/repocreds" + repository6 "github.com/devtron-labs/devtron/client/argocdServer/repository" "github.com/devtron-labs/devtron/client/argocdServer/version" cron2 "github.com/devtron-labs/devtron/client/cron" "github.com/devtron-labs/devtron/client/dashboard" @@ -95,9 +97,9 @@ import ( "github.com/devtron-labs/devtron/internal/sql/repository/bulkUpdate" "github.com/devtron-labs/devtron/internal/sql/repository/chartConfig" "github.com/devtron-labs/devtron/internal/sql/repository/deploymentConfig" - repository7 "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry" + repository9 "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry" "github.com/devtron-labs/devtron/internal/sql/repository/helper" - repository19 "github.com/devtron-labs/devtron/internal/sql/repository/imageTagging" + repository21 "github.com/devtron-labs/devtron/internal/sql/repository/imageTagging" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/sql/repository/resourceGroup" "github.com/devtron-labs/devtron/internal/util" @@ -109,7 +111,7 @@ import ( "github.com/devtron-labs/devtron/pkg/appClone/batch" appStatus2 "github.com/devtron-labs/devtron/pkg/appStatus" "github.com/devtron-labs/devtron/pkg/appStore/chartGroup" - repository25 "github.com/devtron-labs/devtron/pkg/appStore/chartGroup/repository" + repository27 "github.com/devtron-labs/devtron/pkg/appStore/chartGroup/repository" "github.com/devtron-labs/devtron/pkg/appStore/chartProvider" "github.com/devtron-labs/devtron/pkg/appStore/discover/repository" service6 "github.com/devtron-labs/devtron/pkg/appStore/discover/service" @@ -127,70 +129,71 @@ import ( service4 "github.com/devtron-labs/devtron/pkg/appStore/values/service" appWorkflow2 "github.com/devtron-labs/devtron/pkg/appWorkflow" "github.com/devtron-labs/devtron/pkg/argoApplication" - read16 "github.com/devtron-labs/devtron/pkg/argoApplication/read" - "github.com/devtron-labs/devtron/pkg/argoApplication/read/config" + read17 "github.com/devtron-labs/devtron/pkg/argoApplication/read" + config2 "github.com/devtron-labs/devtron/pkg/argoApplication/read/config" "github.com/devtron-labs/devtron/pkg/asyncProvider" "github.com/devtron-labs/devtron/pkg/attributes" "github.com/devtron-labs/devtron/pkg/auth/authentication" "github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin" "github.com/devtron-labs/devtron/pkg/auth/sso" "github.com/devtron-labs/devtron/pkg/auth/user" - repository5 "github.com/devtron-labs/devtron/pkg/auth/user/repository" + repository4 "github.com/devtron-labs/devtron/pkg/auth/user/repository" "github.com/devtron-labs/devtron/pkg/build/artifacts" "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging" - read11 "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging/read" + read12 "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging/read" "github.com/devtron-labs/devtron/pkg/build/git/gitHost" - read15 "github.com/devtron-labs/devtron/pkg/build/git/gitHost/read" - repository23 "github.com/devtron-labs/devtron/pkg/build/git/gitHost/repository" - read10 "github.com/devtron-labs/devtron/pkg/build/git/gitMaterial/read" - repository17 "github.com/devtron-labs/devtron/pkg/build/git/gitMaterial/repository" + read16 "github.com/devtron-labs/devtron/pkg/build/git/gitHost/read" + repository25 "github.com/devtron-labs/devtron/pkg/build/git/gitHost/repository" + read11 "github.com/devtron-labs/devtron/pkg/build/git/gitMaterial/read" + repository19 "github.com/devtron-labs/devtron/pkg/build/git/gitMaterial/repository" "github.com/devtron-labs/devtron/pkg/build/git/gitProvider" read6 "github.com/devtron-labs/devtron/pkg/build/git/gitProvider/read" - repository10 "github.com/devtron-labs/devtron/pkg/build/git/gitProvider/repository" + repository11 "github.com/devtron-labs/devtron/pkg/build/git/gitProvider/repository" "github.com/devtron-labs/devtron/pkg/build/git/gitWebhook" - repository20 "github.com/devtron-labs/devtron/pkg/build/git/gitWebhook/repository" + repository22 "github.com/devtron-labs/devtron/pkg/build/git/gitWebhook/repository" pipeline2 "github.com/devtron-labs/devtron/pkg/build/pipeline" - read9 "github.com/devtron-labs/devtron/pkg/build/pipeline/read" + read10 "github.com/devtron-labs/devtron/pkg/build/pipeline/read" "github.com/devtron-labs/devtron/pkg/bulkAction" "github.com/devtron-labs/devtron/pkg/chart" "github.com/devtron-labs/devtron/pkg/chart/gitOpsConfig" "github.com/devtron-labs/devtron/pkg/chartRepo" "github.com/devtron-labs/devtron/pkg/chartRepo/repository" - cluster2 "github.com/devtron-labs/devtron/pkg/cluster" + "github.com/devtron-labs/devtron/pkg/cluster" "github.com/devtron-labs/devtron/pkg/cluster/environment" read2 "github.com/devtron-labs/devtron/pkg/cluster/environment/read" "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" rbac2 "github.com/devtron-labs/devtron/pkg/cluster/rbac" "github.com/devtron-labs/devtron/pkg/cluster/read" - repository4 "github.com/devtron-labs/devtron/pkg/cluster/repository" + repository5 "github.com/devtron-labs/devtron/pkg/cluster/repository" "github.com/devtron-labs/devtron/pkg/clusterTerminalAccess" "github.com/devtron-labs/devtron/pkg/commonService" - "github.com/devtron-labs/devtron/pkg/configDiff" + "github.com/devtron-labs/devtron/pkg/config/configDiff" + read9 "github.com/devtron-labs/devtron/pkg/config/read" delete2 "github.com/devtron-labs/devtron/pkg/delete" "github.com/devtron-labs/devtron/pkg/deployment/common" "github.com/devtron-labs/devtron/pkg/deployment/deployedApp" "github.com/devtron-labs/devtron/pkg/deployment/deployedApp/status/resourceTree" - config2 "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" + "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/validation" "github.com/devtron-labs/devtron/pkg/deployment/manifest" "github.com/devtron-labs/devtron/pkg/deployment/manifest/configMapAndSecret" - read13 "github.com/devtron-labs/devtron/pkg/deployment/manifest/configMapAndSecret/read" + read14 "github.com/devtron-labs/devtron/pkg/deployment/manifest/configMapAndSecret/read" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deployedAppMetrics" - repository13 "github.com/devtron-labs/devtron/pkg/deployment/manifest/deployedAppMetrics/repository" + repository16 "github.com/devtron-labs/devtron/pkg/deployment/manifest/deployedAppMetrics/repository" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/chartRef" read7 "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/read" "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" - repository22 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/userDeploymentRequest/repository" + repository24 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/userDeploymentRequest/repository" service3 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/userDeploymentRequest/service" "github.com/devtron-labs/devtron/pkg/deploymentGroup" "github.com/devtron-labs/devtron/pkg/devtronResource" "github.com/devtron-labs/devtron/pkg/devtronResource/history/deployment/cdPipeline" read8 "github.com/devtron-labs/devtron/pkg/devtronResource/read" - repository12 "github.com/devtron-labs/devtron/pkg/devtronResource/repository" + repository13 "github.com/devtron-labs/devtron/pkg/devtronResource/repository" "github.com/devtron-labs/devtron/pkg/dockerRegistry" "github.com/devtron-labs/devtron/pkg/eventProcessor" "github.com/devtron-labs/devtron/pkg/eventProcessor/celEvaluator" @@ -200,18 +203,20 @@ import ( "github.com/devtron-labs/devtron/pkg/fluxApplication" "github.com/devtron-labs/devtron/pkg/generateManifest" "github.com/devtron-labs/devtron/pkg/genericNotes" - repository8 "github.com/devtron-labs/devtron/pkg/genericNotes/repository" + repository10 "github.com/devtron-labs/devtron/pkg/genericNotes/repository" "github.com/devtron-labs/devtron/pkg/gitops" "github.com/devtron-labs/devtron/pkg/imageDigestPolicy" + config4 "github.com/devtron-labs/devtron/pkg/infraConfig/config" repository14 "github.com/devtron-labs/devtron/pkg/infraConfig/repository" + "github.com/devtron-labs/devtron/pkg/infraConfig/repository/audit" service2 "github.com/devtron-labs/devtron/pkg/infraConfig/service" - "github.com/devtron-labs/devtron/pkg/infraConfig/units" + audit2 "github.com/devtron-labs/devtron/pkg/infraConfig/service/audit" k8s2 "github.com/devtron-labs/devtron/pkg/k8s" application2 "github.com/devtron-labs/devtron/pkg/k8s/application" "github.com/devtron-labs/devtron/pkg/k8s/capacity" "github.com/devtron-labs/devtron/pkg/k8s/informer" "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs" - repository24 "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs/repository" + repository26 "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs/repository" "github.com/devtron-labs/devtron/pkg/module" "github.com/devtron-labs/devtron/pkg/module/repo" "github.com/devtron-labs/devtron/pkg/module/store" @@ -219,15 +224,19 @@ import ( "github.com/devtron-labs/devtron/pkg/pipeline" "github.com/devtron-labs/devtron/pkg/pipeline/executors" "github.com/devtron-labs/devtron/pkg/pipeline/history" - repository18 "github.com/devtron-labs/devtron/pkg/pipeline/history/repository" + repository20 "github.com/devtron-labs/devtron/pkg/pipeline/history/repository" "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders" - repository15 "github.com/devtron-labs/devtron/pkg/pipeline/repository" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/ci" + "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/job" + repository17 "github.com/devtron-labs/devtron/pkg/pipeline/repository" "github.com/devtron-labs/devtron/pkg/pipeline/types" "github.com/devtron-labs/devtron/pkg/plugin" - repository16 "github.com/devtron-labs/devtron/pkg/plugin/repository" + repository18 "github.com/devtron-labs/devtron/pkg/plugin/repository" "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning" - read12 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/read" - repository9 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" + read13 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/read" + repository23 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" + "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool" + repository15 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/repository" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" "github.com/devtron-labs/devtron/pkg/resourceQualifiers" "github.com/devtron-labs/devtron/pkg/server" @@ -236,15 +245,15 @@ import ( "github.com/devtron-labs/devtron/pkg/sql" "github.com/devtron-labs/devtron/pkg/team" read3 "github.com/devtron-labs/devtron/pkg/team/read" - repository6 "github.com/devtron-labs/devtron/pkg/team/repository" + repository8 "github.com/devtron-labs/devtron/pkg/team/repository" "github.com/devtron-labs/devtron/pkg/terminal" util3 "github.com/devtron-labs/devtron/pkg/util" "github.com/devtron-labs/devtron/pkg/variables" "github.com/devtron-labs/devtron/pkg/variables/parsers" - repository11 "github.com/devtron-labs/devtron/pkg/variables/repository" + repository12 "github.com/devtron-labs/devtron/pkg/variables/repository" "github.com/devtron-labs/devtron/pkg/webhook/helm" "github.com/devtron-labs/devtron/pkg/workflow/cd" - read14 "github.com/devtron-labs/devtron/pkg/workflow/cd/read" + read15 "github.com/devtron-labs/devtron/pkg/workflow/cd/read" "github.com/devtron-labs/devtron/pkg/workflow/dag" status2 "github.com/devtron-labs/devtron/pkg/workflow/status" util2 "github.com/devtron-labs/devtron/util" @@ -284,77 +293,100 @@ func InitializeApp() (*App, error) { attributesServiceImpl := attributes.NewAttributesServiceImpl(sugaredLogger, attributesRepositoryImpl) grafanaClientImpl := grafana.NewGrafanaClientImpl(sugaredLogger, httpClient, grafanaClientConfig, attributesServiceImpl) installedAppRepositoryImpl := repository3.NewInstalledAppRepositoryImpl(sugaredLogger, db) - connectionConfig, err := connection.GetConfig() + gitOpsConfigRepositoryImpl := repository2.NewGitOpsConfigRepositoryImpl(sugaredLogger, db) + defaultAuthPolicyRepositoryImpl := repository4.NewDefaultAuthPolicyRepositoryImpl(db, sugaredLogger) + defaultAuthRoleRepositoryImpl := repository4.NewDefaultAuthRoleRepositoryImpl(db, sugaredLogger) + userAuthRepositoryImpl := repository4.NewUserAuthRepositoryImpl(db, sugaredLogger, defaultAuthPolicyRepositoryImpl, defaultAuthRoleRepositoryImpl) + userRepositoryImpl := repository4.NewUserRepositoryImpl(db, sugaredLogger) + roleGroupRepositoryImpl := repository4.NewRoleGroupRepositoryImpl(db, sugaredLogger) + runtimeConfig, err := client.GetRuntimeConfig() if err != nil { return nil, err } - settingsManager, err := connection.SettingsManager(connectionConfig) + k8sClient, err := client.NewK8sClient(runtimeConfig) if err != nil { return nil, err } - moduleRepositoryImpl := moduleRepo.NewModuleRepositoryImpl(db) + dexConfig, err := client.BuildDexConfig(k8sClient) + if err != nil { + return nil, err + } + settings, err := client.GetSettings(dexConfig) + if err != nil { + return nil, err + } + apiTokenSecretStore := apiTokenAuth.InitApiTokenSecretStore() + sessionManager := middleware.NewSessionManager(settings, dexConfig, apiTokenSecretStore) + rbacPolicyDataRepositoryImpl := repository4.NewRbacPolicyDataRepositoryImpl(sugaredLogger, db) + rbacRoleDataRepositoryImpl := repository4.NewRbacRoleDataRepositoryImpl(sugaredLogger, db) + rbacDataCacheFactoryImpl := repository4.NewRbacDataCacheFactoryImpl(sugaredLogger, rbacPolicyDataRepositoryImpl, rbacRoleDataRepositoryImpl) + userCommonServiceImpl, err := user.NewUserCommonServiceImpl(userAuthRepositoryImpl, sugaredLogger, userRepositoryImpl, roleGroupRepositoryImpl, sessionManager, rbacDataCacheFactoryImpl) + if err != nil { + return nil, err + } + userAuditRepositoryImpl := repository4.NewUserAuditRepositoryImpl(db) + userAuditServiceImpl := user.NewUserAuditServiceImpl(sugaredLogger, userAuditRepositoryImpl) + userServiceImpl := user.NewUserServiceImpl(userAuthRepositoryImpl, sugaredLogger, userRepositoryImpl, roleGroupRepositoryImpl, sessionManager, userCommonServiceImpl, userAuditServiceImpl) environmentVariables, err := util2.GetEnvironmentVariables() if err != nil { return nil, err } - runtimeConfig, err := k8s.GetRuntimeConfig() + gitOpsConfigReadServiceImpl := config.NewGitOpsConfigReadServiceImpl(sugaredLogger, gitOpsConfigRepositoryImpl, userServiceImpl, environmentVariables) + clusterRepositoryImpl := repository5.NewClusterRepositoryImpl(db, sugaredLogger) + k8sRuntimeConfig, err := k8s.GetRuntimeConfig() if err != nil { return nil, err } - k8sServiceImpl := k8s.NewK8sUtil(sugaredLogger, runtimeConfig) - clusterRepositoryImpl := repository4.NewClusterRepositoryImpl(db, sugaredLogger) - argoApplicationConfigServiceImpl := config.NewArgoApplicationConfigServiceImpl(sugaredLogger, k8sServiceImpl, clusterRepositoryImpl) + k8sServiceImpl := k8s.NewK8sUtil(sugaredLogger, k8sRuntimeConfig) + syncMap := informer.NewGlobalMapClusterNamespace() + k8sInformerFactoryImpl := informer.NewK8sInformerFactoryImpl(sugaredLogger, syncMap, k8sServiceImpl) + cronLoggerImpl := cron.NewCronLoggerImpl(sugaredLogger) clusterReadServiceImpl := read.NewClusterReadServiceImpl(sugaredLogger, clusterRepositoryImpl) - k8sCommonServiceImpl := k8s2.NewK8sCommonServiceImpl(sugaredLogger, k8sServiceImpl, argoApplicationConfigServiceImpl, clusterReadServiceImpl) - versionServiceImpl := version.NewVersionServiceImpl(sugaredLogger) - gitOpsConfigRepositoryImpl := repository2.NewGitOpsConfigRepositoryImpl(sugaredLogger, db) - defaultAuthPolicyRepositoryImpl := repository5.NewDefaultAuthPolicyRepositoryImpl(db, sugaredLogger) - defaultAuthRoleRepositoryImpl := repository5.NewDefaultAuthRoleRepositoryImpl(db, sugaredLogger) - userAuthRepositoryImpl := repository5.NewUserAuthRepositoryImpl(db, sugaredLogger, defaultAuthPolicyRepositoryImpl, defaultAuthRoleRepositoryImpl) - userRepositoryImpl := repository5.NewUserRepositoryImpl(db, sugaredLogger) - roleGroupRepositoryImpl := repository5.NewRoleGroupRepositoryImpl(db, sugaredLogger) - clientRuntimeConfig, err := client.GetRuntimeConfig() + clusterServiceImpl, err := cluster.NewClusterServiceImpl(clusterRepositoryImpl, sugaredLogger, k8sServiceImpl, k8sInformerFactoryImpl, userAuthRepositoryImpl, userRepositoryImpl, roleGroupRepositoryImpl, environmentVariables, cronLoggerImpl, clusterReadServiceImpl) if err != nil { return nil, err } - k8sClient, err := client.NewK8sClient(clientRuntimeConfig) + beanConfig, err := bean.GetConfig() if err != nil { return nil, err } - dexConfig, err := client.BuildDexConfig(k8sClient) + settingsManager, err := connection.SettingsManager(beanConfig) if err != nil { return nil, err } - settings, err := client.GetSettings(dexConfig) + moduleRepositoryImpl := moduleRepo.NewModuleRepositoryImpl(db) + argoApplicationConfigServiceImpl := config2.NewArgoApplicationConfigServiceImpl(sugaredLogger, k8sServiceImpl, clusterRepositoryImpl) + k8sCommonServiceImpl := k8s2.NewK8sCommonServiceImpl(sugaredLogger, k8sServiceImpl, argoApplicationConfigServiceImpl, clusterReadServiceImpl) + versionServiceImpl := version.NewVersionServiceImpl(sugaredLogger) + acdAuthConfig, err := util3.GetACDAuthConfig() if err != nil { return nil, err } - apiTokenSecretStore := apiTokenAuth.InitApiTokenSecretStore() - sessionManager := middleware.NewSessionManager(settings, dexConfig, apiTokenSecretStore) - rbacPolicyDataRepositoryImpl := repository5.NewRbacPolicyDataRepositoryImpl(sugaredLogger, db) - rbacRoleDataRepositoryImpl := repository5.NewRbacRoleDataRepositoryImpl(sugaredLogger, db) - rbacDataCacheFactoryImpl := repository5.NewRbacDataCacheFactoryImpl(sugaredLogger, rbacPolicyDataRepositoryImpl, rbacRoleDataRepositoryImpl) - userCommonServiceImpl, err := user.NewUserCommonServiceImpl(userAuthRepositoryImpl, sugaredLogger, userRepositoryImpl, roleGroupRepositoryImpl, sessionManager, rbacDataCacheFactoryImpl) + argoCDConfigGetterImpl := config3.NewArgoCDConfigGetter(beanConfig, environmentVariables, acdAuthConfig, clusterReadServiceImpl, sugaredLogger, k8sServiceImpl) + argoCDConnectionManagerImpl, err := connection.NewArgoCDConnectionManagerImpl(sugaredLogger, settingsManager, moduleRepositoryImpl, environmentVariables, k8sServiceImpl, k8sCommonServiceImpl, versionServiceImpl, gitOpsConfigReadServiceImpl, k8sRuntimeConfig, argoCDConfigGetterImpl) if err != nil { return nil, err } - userAuditRepositoryImpl := repository5.NewUserAuditRepositoryImpl(db) - userAuditServiceImpl := user.NewUserAuditServiceImpl(sugaredLogger, userAuditRepositoryImpl) - userServiceImpl := user.NewUserServiceImpl(userAuthRepositoryImpl, sugaredLogger, userRepositoryImpl, roleGroupRepositoryImpl, sessionManager, userCommonServiceImpl, userAuditServiceImpl) - gitOpsConfigReadServiceImpl := config2.NewGitOpsConfigReadServiceImpl(sugaredLogger, gitOpsConfigRepositoryImpl, userServiceImpl, environmentVariables) - argoCDConnectionManagerImpl, err := connection.NewArgoCDConnectionManagerImpl(sugaredLogger, settingsManager, moduleRepositoryImpl, environmentVariables, k8sServiceImpl, k8sCommonServiceImpl, versionServiceImpl, gitOpsConfigReadServiceImpl, runtimeConfig) + serviceClientImpl := application.NewApplicationClientImpl(sugaredLogger, argoCDConnectionManagerImpl) + repositoryServiceClientImpl := repository6.NewServiceClientImpl(sugaredLogger, argoCDConnectionManagerImpl) + clusterServiceClientImpl := cluster2.NewServiceClientImpl(sugaredLogger, argoCDConnectionManagerImpl) + serviceClientImpl2 := repository7.NewServiceClientImpl(sugaredLogger, argoCDConnectionManagerImpl) + certificateServiceClientImpl := certificate.NewServiceClientImpl(sugaredLogger, argoCDConnectionManagerImpl) + acdConfig, err := argocdServer.GetACDDeploymentConfig() if err != nil { return nil, err } - serviceClientImpl := cluster.NewServiceClientImpl(sugaredLogger, argoCDConnectionManagerImpl) - syncMap := informer.NewGlobalMapClusterNamespace() - k8sInformerFactoryImpl := informer.NewK8sInformerFactoryImpl(sugaredLogger, syncMap, k8sServiceImpl) - cronLoggerImpl := cron.NewCronLoggerImpl(sugaredLogger) - clusterServiceImpl, err := cluster2.NewClusterServiceImpl(clusterRepositoryImpl, sugaredLogger, k8sServiceImpl, k8sInformerFactoryImpl, userAuthRepositoryImpl, userRepositoryImpl, roleGroupRepositoryImpl, environmentVariables, cronLoggerImpl, clusterReadServiceImpl) + gitFactory, err := git.NewGitFactory(sugaredLogger, gitOpsConfigReadServiceImpl) if err != nil { return nil, err } - clusterServiceImplExtended := cluster2.NewClusterServiceImplExtended(environmentRepositoryImpl, grafanaClientImpl, installedAppRepositoryImpl, serviceClientImpl, gitOpsConfigReadServiceImpl, clusterServiceImpl) + chartTemplateServiceImpl := util.NewChartTemplateServiceImpl(sugaredLogger) + gitOperationServiceImpl := git.NewGitOperationServiceImpl(sugaredLogger, gitFactory, gitOpsConfigReadServiceImpl, chartTemplateServiceImpl, environmentVariables) + runnable := asyncProvider.NewAsyncRunnable(sugaredLogger) + repositoryCredsK8sClientImpl := repoCredsK8sClient.NewRepositoryCredsK8sClientImpl(sugaredLogger, k8sServiceImpl) + argoClientWrapperServiceEAImpl := argocdServer.NewArgoClientWrapperServiceEAImpl(sugaredLogger, repositoryCredsK8sClientImpl, argoCDConfigGetterImpl) + argoClientWrapperServiceImpl := argocdServer.NewArgoClientWrapperServiceImpl(serviceClientImpl, repositoryServiceClientImpl, clusterServiceClientImpl, serviceClientImpl2, certificateServiceClientImpl, sugaredLogger, acdConfig, gitOpsConfigReadServiceImpl, gitOperationServiceImpl, runnable, argoCDConfigGetterImpl, argoClientWrapperServiceEAImpl) + clusterServiceImplExtended := cluster.NewClusterServiceImplExtended(environmentRepositoryImpl, grafanaClientImpl, installedAppRepositoryImpl, gitOpsConfigReadServiceImpl, clusterServiceImpl, argoClientWrapperServiceImpl) loginService := middleware.NewUserLogin(sessionManager, k8sClient) userAuthServiceImpl := user.NewUserAuthServiceImpl(userAuthRepositoryImpl, sessionManager, loginService, sugaredLogger, userRepositoryImpl, roleGroupRepositoryImpl, userServiceImpl) environmentServiceImpl := environment.NewEnvironmentServiceImpl(environmentRepositoryImpl, clusterServiceImplExtended, sugaredLogger, k8sServiceImpl, k8sInformerFactoryImpl, userAuthServiceImpl, attributesRepositoryImpl, clusterReadServiceImpl) @@ -375,22 +407,17 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - teamRepositoryImpl := repository6.NewTeamRepositoryImpl(db) + teamRepositoryImpl := repository8.NewTeamRepositoryImpl(db) teamReadServiceImpl := read3.NewTeamReadService(sugaredLogger, teamRepositoryImpl) teamServiceImpl := team.NewTeamServiceImpl(sugaredLogger, teamRepositoryImpl, userAuthServiceImpl, teamReadServiceImpl) appRepositoryImpl := app.NewAppRepositoryImpl(db, sugaredLogger) pipelineRepositoryImpl := pipelineConfig.NewPipelineRepositoryImpl(db, sugaredLogger) chartRepoRepositoryImpl := chartRepoRepository.NewChartRepoRepositoryImpl(db) - acdAuthConfig, err := util3.GetACDAuthConfig() - if err != nil { - return nil, err - } serverEnvConfigServerEnvConfig, err := serverEnvConfig.ParseServerEnvConfig() if err != nil { return nil, err } - repositorySecretImpl := repoCredsK8sClient.NewRepositorySecret(sugaredLogger, k8sServiceImpl, clusterServiceImplExtended, acdAuthConfig) - chartRepositoryServiceImpl := chartRepo.NewChartRepositoryServiceImpl(sugaredLogger, chartRepoRepositoryImpl, k8sServiceImpl, clusterServiceImplExtended, acdAuthConfig, httpClient, serverEnvConfigServerEnvConfig, repositorySecretImpl) + chartRepositoryServiceImpl := chartRepo.NewChartRepositoryServiceImpl(sugaredLogger, chartRepoRepositoryImpl, k8sServiceImpl, acdAuthConfig, httpClient, serverEnvConfigServerEnvConfig, argoClientWrapperServiceImpl, clusterReadServiceImpl) helmClientConfig, err := gRPC.GetConfig() if err != nil { return nil, err @@ -412,20 +439,20 @@ func InitializeApp() (*App, error) { } helmAppReadServiceImpl := read5.NewHelmAppReadServiceImpl(sugaredLogger, clusterReadServiceImpl) helmAppServiceImpl := service.NewHelmAppServiceImpl(sugaredLogger, clusterServiceImplExtended, helmAppClientImpl, pumpImpl, enforcerUtilHelmImpl, serverDataStoreServerDataStore, serverEnvConfigServerEnvConfig, appStoreApplicationVersionRepositoryImpl, environmentServiceImpl, pipelineRepositoryImpl, installedAppRepositoryImpl, appRepositoryImpl, clusterRepositoryImpl, k8sServiceImpl, helmReleaseConfig, helmAppReadServiceImpl) - dockerArtifactStoreRepositoryImpl := repository7.NewDockerArtifactStoreRepositoryImpl(db) - dockerRegistryIpsConfigRepositoryImpl := repository7.NewDockerRegistryIpsConfigRepositoryImpl(db) - ociRegistryConfigRepositoryImpl := repository7.NewOCIRegistryConfigRepositoryImpl(db) - dockerRegistryConfigImpl := pipeline.NewDockerRegistryConfigImpl(sugaredLogger, helmAppServiceImpl, dockerArtifactStoreRepositoryImpl, dockerRegistryIpsConfigRepositoryImpl, ociRegistryConfigRepositoryImpl, repositorySecretImpl) + dockerArtifactStoreRepositoryImpl := repository9.NewDockerArtifactStoreRepositoryImpl(db) + dockerRegistryIpsConfigRepositoryImpl := repository9.NewDockerRegistryIpsConfigRepositoryImpl(db) + ociRegistryConfigRepositoryImpl := repository9.NewOCIRegistryConfigRepositoryImpl(db) + dockerRegistryConfigImpl := pipeline.NewDockerRegistryConfigImpl(sugaredLogger, helmAppServiceImpl, dockerArtifactStoreRepositoryImpl, dockerRegistryIpsConfigRepositoryImpl, ociRegistryConfigRepositoryImpl, argoClientWrapperServiceImpl) deleteServiceExtendedImpl := delete2.NewDeleteServiceExtendedImpl(sugaredLogger, teamServiceImpl, clusterServiceImplExtended, environmentServiceImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, chartRepositoryServiceImpl, installedAppRepositoryImpl, dockerRegistryConfigImpl, dockerArtifactStoreRepositoryImpl, k8sServiceImpl, k8sInformerFactoryImpl) environmentRestHandlerImpl := cluster3.NewEnvironmentRestHandlerImpl(environmentServiceImpl, environmentReadServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl, k8sServiceImpl, k8sCommonServiceImpl) environmentRouterImpl := cluster3.NewEnvironmentRouterImpl(environmentRestHandlerImpl) transactionUtilImpl := sql.NewTransactionUtilImpl(db) - genericNoteRepositoryImpl := repository8.NewGenericNoteRepositoryImpl(db, transactionUtilImpl) - genericNoteHistoryRepositoryImpl := repository8.NewGenericNoteHistoryRepositoryImpl(db, transactionUtilImpl) + genericNoteRepositoryImpl := repository10.NewGenericNoteRepositoryImpl(db, transactionUtilImpl) + genericNoteHistoryRepositoryImpl := repository10.NewGenericNoteHistoryRepositoryImpl(db, transactionUtilImpl) genericNoteHistoryServiceImpl := genericNotes.NewGenericNoteHistoryServiceImpl(genericNoteHistoryRepositoryImpl, sugaredLogger) genericNoteServiceImpl := genericNotes.NewGenericNoteServiceImpl(genericNoteRepositoryImpl, genericNoteHistoryServiceImpl, userRepositoryImpl, sugaredLogger) - clusterDescriptionRepositoryImpl := repository4.NewClusterDescriptionRepositoryImpl(db, sugaredLogger) - clusterDescriptionServiceImpl := cluster2.NewClusterDescriptionServiceImpl(clusterDescriptionRepositoryImpl, userRepositoryImpl, sugaredLogger) + clusterDescriptionRepositoryImpl := repository5.NewClusterDescriptionRepositoryImpl(db, sugaredLogger) + clusterDescriptionServiceImpl := cluster.NewClusterDescriptionServiceImpl(clusterDescriptionRepositoryImpl, userRepositoryImpl, sugaredLogger) ciPipelineRepositoryImpl := pipelineConfig.NewCiPipelineRepositoryImpl(db, sugaredLogger, transactionUtilImpl) enforcerUtilImpl := rbac.NewEnforcerUtilImpl(sugaredLogger, teamRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, clusterRepositoryImpl, enforcerImpl, dbMigrationServiceImpl, teamReadServiceImpl) clusterRbacServiceImpl := rbac2.NewClusterRbacServiceImpl(environmentServiceImpl, enforcerImpl, enforcerUtilImpl, clusterServiceImplExtended, sugaredLogger, userServiceImpl, clusterReadServiceImpl) @@ -435,8 +462,60 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } + chartRepositoryImpl := chartRepoRepository.NewChartRepository(db, transactionUtilImpl) + envConfigOverrideRepositoryImpl := chartConfig.NewEnvConfigOverrideRepository(db) + gitProviderRepositoryImpl := repository11.NewGitProviderRepositoryImpl(db) + gitProviderReadServiceImpl := read6.NewGitProviderReadService(sugaredLogger, gitProviderRepositoryImpl) + envConfigOverrideReadServiceImpl := read7.NewEnvConfigOverrideReadServiceImpl(envConfigOverrideRepositoryImpl, sugaredLogger) + commonServiceImpl := commonService.NewCommonServiceImpl(sugaredLogger, chartRepositoryImpl, envConfigOverrideRepositoryImpl, dockerArtifactStoreRepositoryImpl, attributesRepositoryImpl, environmentRepositoryImpl, appRepositoryImpl, gitOpsConfigReadServiceImpl, gitProviderReadServiceImpl, envConfigOverrideReadServiceImpl, teamReadServiceImpl) + configMapRepositoryImpl := chartConfig.NewConfigMapRepositoryImpl(sugaredLogger, db) + mergeUtil := util.MergeUtil{ + Logger: sugaredLogger, + } + scopedVariableRepositoryImpl := repository12.NewScopedVariableRepository(db, sugaredLogger, transactionUtilImpl) + devtronResourceSearchableKeyRepositoryImpl := repository13.NewDevtronResourceSearchableKeyRepositoryImpl(sugaredLogger, db) + devtronResourceSearchableKeyServiceImpl, err := read8.NewDevtronResourceSearchableKeyServiceImpl(sugaredLogger, devtronResourceSearchableKeyRepositoryImpl) + if err != nil { + return nil, err + } + qualifiersMappingRepositoryImpl, err := resourceQualifiers.NewQualifiersMappingRepositoryImpl(db, sugaredLogger, transactionUtilImpl) + if err != nil { + return nil, err + } + qualifierMappingServiceImpl, err := resourceQualifiers.NewQualifierMappingServiceImpl(sugaredLogger, qualifiersMappingRepositoryImpl, devtronResourceSearchableKeyServiceImpl) + if err != nil { + return nil, err + } + scopedVariableServiceImpl, err := variables.NewScopedVariableServiceImpl(sugaredLogger, scopedVariableRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, devtronResourceSearchableKeyServiceImpl, clusterRepositoryImpl, qualifierMappingServiceImpl) + if err != nil { + return nil, err + } + variableEntityMappingRepositoryImpl := repository12.NewVariableEntityMappingRepository(sugaredLogger, db, transactionUtilImpl) + variableEntityMappingServiceImpl := variables.NewVariableEntityMappingServiceImpl(variableEntityMappingRepositoryImpl, sugaredLogger) + variableSnapshotHistoryRepositoryImpl := repository12.NewVariableSnapshotHistoryRepository(sugaredLogger, db) + variableSnapshotHistoryServiceImpl := variables.NewVariableSnapshotHistoryServiceImpl(variableSnapshotHistoryRepositoryImpl, sugaredLogger) + variableTemplateParserImpl, err := parsers.NewVariableTemplateParserImpl(sugaredLogger) + if err != nil { + return nil, err + } + scopedVariableCMCSManagerImpl, err := variables.NewScopedVariableCMCSManagerImpl(sugaredLogger, scopedVariableServiceImpl, variableEntityMappingServiceImpl, variableSnapshotHistoryServiceImpl, variableTemplateParserImpl) + if err != nil { + return nil, err + } + configReadServiceImpl := read9.NewConfigReadServiceImpl(sugaredLogger, commonServiceImpl, configMapRepositoryImpl, mergeUtil, scopedVariableCMCSManagerImpl) + globalCMCSRepositoryImpl := repository2.NewGlobalCMCSRepositoryImpl(sugaredLogger, db) + globalCMCSServiceImpl := pipeline.NewGlobalCMCSServiceImpl(sugaredLogger, globalCMCSRepositoryImpl) + argoWorkflowExecutorImpl := executors.NewArgoWorkflowExecutorImpl(sugaredLogger) + systemWorkflowExecutorImpl := executors.NewSystemWorkflowExecutorImpl(sugaredLogger, k8sServiceImpl) + infraConfigAuditRepositoryImpl := audit.NewInfraConfigAuditRepositoryImpl(db) + infraConfigAuditServiceImpl := audit2.NewInfraConfigAuditServiceImpl(sugaredLogger, infraConfigAuditRepositoryImpl, transactionUtilImpl) + infraGetter, err := job.NewJobInfraGetter(sugaredLogger, configReadServiceImpl, infraConfigAuditServiceImpl) + if err != nil { + return nil, err + } + infraConfigRepositoryImpl := repository14.NewInfraProfileRepositoryImpl(db, transactionUtilImpl) pipelineOverrideRepositoryImpl := chartConfig.NewPipelineOverrideRepository(db) - mergeUtil := &util.MergeUtil{ + utilMergeUtil := &util.MergeUtil{ Logger: sugaredLogger, } eventClientConfig, err := client2.GetEventClientConfig() @@ -467,8 +546,8 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - scanToolMetadataRepositoryImpl := repository9.NewScanToolMetadataRepositoryImpl(db, sugaredLogger) - scanToolMetadataServiceImpl := imageScanning.NewScanToolMetadataServiceImpl(sugaredLogger, scanToolMetadataRepositoryImpl) + scanToolMetadataRepositoryImpl := repository15.NewScanToolMetadataRepositoryImpl(db, sugaredLogger) + scanToolMetadataServiceImpl := scanTool.NewScanToolMetadataServiceImpl(sugaredLogger, scanToolMetadataRepositoryImpl) moduleServiceImpl := module.NewModuleServiceImpl(sugaredLogger, serverEnvConfigServerEnvConfig, moduleRepositoryImpl, moduleActionAuditLogRepositoryImpl, helmAppServiceImpl, serverDataStoreServerDataStore, serverCacheServiceImpl, moduleCacheServiceImpl, moduleCronServiceImpl, moduleServiceHelperImpl, moduleResourceStatusRepositoryImpl, scanToolMetadataServiceImpl) eventRESTClientImpl := client2.NewEventRESTClientImpl(sugaredLogger, httpClient, eventClientConfig, pubSubClientServiceImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, attributesRepositoryImpl, moduleServiceImpl) cdWorkflowRepositoryImpl := pipelineConfig.NewCdWorkflowRepositoryImpl(db, sugaredLogger) @@ -476,15 +555,6 @@ func InitializeApp() (*App, error) { ciPipelineMaterialRepositoryImpl := pipelineConfig.NewCiPipelineMaterialRepositoryImpl(db, sugaredLogger) ciArtifactRepositoryImpl := repository2.NewCiArtifactRepositoryImpl(db, sugaredLogger) eventSimpleFactoryImpl := client2.NewEventSimpleFactoryImpl(sugaredLogger, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, ciWorkflowRepositoryImpl, ciPipelineMaterialRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, userRepositoryImpl, environmentRepositoryImpl, ciArtifactRepositoryImpl) - applicationServiceClientImpl := application.NewApplicationClientImpl(sugaredLogger, argoCDConnectionManagerImpl) - configMapRepositoryImpl := chartConfig.NewConfigMapRepositoryImpl(sugaredLogger, db) - chartRepositoryImpl := chartRepoRepository.NewChartRepository(db, transactionUtilImpl) - envConfigOverrideRepositoryImpl := chartConfig.NewEnvConfigOverrideRepository(db) - gitProviderRepositoryImpl := repository10.NewGitProviderRepositoryImpl(db) - gitProviderReadServiceImpl := read6.NewGitProviderReadService(sugaredLogger, gitProviderRepositoryImpl) - envConfigOverrideReadServiceImpl := read7.NewEnvConfigOverrideReadServiceImpl(envConfigOverrideRepositoryImpl, sugaredLogger) - commonServiceImpl := commonService.NewCommonServiceImpl(sugaredLogger, chartRepositoryImpl, envConfigOverrideRepositoryImpl, dockerArtifactStoreRepositoryImpl, attributesRepositoryImpl, environmentRepositoryImpl, appRepositoryImpl, gitOpsConfigReadServiceImpl, gitProviderReadServiceImpl, envConfigOverrideReadServiceImpl, teamReadServiceImpl) - chartTemplateServiceImpl := util.NewChartTemplateServiceImpl(sugaredLogger) pipelineStatusTimelineRepositoryImpl := pipelineConfig.NewPipelineStatusTimelineRepositoryImpl(db, sugaredLogger) pipelineStatusTimelineResourcesRepositoryImpl := pipelineConfig.NewPipelineStatusTimelineResourcesRepositoryImpl(db, sugaredLogger) pipelineStatusTimelineResourcesServiceImpl := status.NewPipelineStatusTimelineResourcesServiceImpl(db, sugaredLogger, pipelineStatusTimelineResourcesRepositoryImpl) @@ -500,50 +570,8 @@ func InitializeApp() (*App, error) { } appStatusServiceImpl := appStatus2.NewAppStatusServiceImpl(appStatusRepositoryImpl, sugaredLogger, enforcerImpl, enforcerUtilImpl) installedAppReadServiceImpl := read4.NewInstalledAppReadServiceImpl(installedAppReadServiceEAImpl) - scopedVariableRepositoryImpl := repository11.NewScopedVariableRepository(db, sugaredLogger, transactionUtilImpl) - devtronResourceSearchableKeyRepositoryImpl := repository12.NewDevtronResourceSearchableKeyRepositoryImpl(sugaredLogger, db) - devtronResourceSearchableKeyServiceImpl, err := read8.NewDevtronResourceSearchableKeyServiceImpl(sugaredLogger, devtronResourceSearchableKeyRepositoryImpl) - if err != nil { - return nil, err - } - qualifiersMappingRepositoryImpl, err := resourceQualifiers.NewQualifiersMappingRepositoryImpl(db, sugaredLogger, transactionUtilImpl) - if err != nil { - return nil, err - } - qualifierMappingServiceImpl, err := resourceQualifiers.NewQualifierMappingServiceImpl(sugaredLogger, qualifiersMappingRepositoryImpl, devtronResourceSearchableKeyServiceImpl) - if err != nil { - return nil, err - } - scopedVariableServiceImpl, err := variables.NewScopedVariableServiceImpl(sugaredLogger, scopedVariableRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, devtronResourceSearchableKeyServiceImpl, clusterRepositoryImpl, qualifierMappingServiceImpl) - if err != nil { - return nil, err - } - variableEntityMappingRepositoryImpl := repository11.NewVariableEntityMappingRepository(sugaredLogger, db, transactionUtilImpl) - variableEntityMappingServiceImpl := variables.NewVariableEntityMappingServiceImpl(variableEntityMappingRepositoryImpl, sugaredLogger) - variableSnapshotHistoryRepositoryImpl := repository11.NewVariableSnapshotHistoryRepository(sugaredLogger, db) - variableSnapshotHistoryServiceImpl := variables.NewVariableSnapshotHistoryServiceImpl(variableSnapshotHistoryRepositoryImpl, sugaredLogger) - variableTemplateParserImpl, err := parsers.NewVariableTemplateParserImpl(sugaredLogger) - if err != nil { - return nil, err - } - scopedVariableCMCSManagerImpl, err := variables.NewScopedVariableCMCSManagerImpl(sugaredLogger, scopedVariableServiceImpl, variableEntityMappingServiceImpl, variableSnapshotHistoryServiceImpl, variableTemplateParserImpl) - if err != nil { - return nil, err - } - acdConfig, err := argocdServer.GetACDDeploymentConfig() - if err != nil { - return nil, err - } - gitFactory, err := git.NewGitFactory(sugaredLogger, gitOpsConfigReadServiceImpl) - if err != nil { - return nil, err - } - gitOperationServiceImpl := git.NewGitOperationServiceImpl(sugaredLogger, gitFactory, gitOpsConfigReadServiceImpl, chartTemplateServiceImpl, environmentVariables) chartRefRepositoryImpl := chartRepoRepository.NewChartRefRepositoryImpl(db) - utilMergeUtil := util.MergeUtil{ - Logger: sugaredLogger, - } - chartRefServiceImpl := chartRef.NewChartRefServiceImpl(sugaredLogger, chartRefRepositoryImpl, chartTemplateServiceImpl, chartRepositoryImpl, utilMergeUtil) + chartRefServiceImpl := chartRef.NewChartRefServiceImpl(sugaredLogger, chartRefRepositoryImpl, chartTemplateServiceImpl, chartRepositoryImpl, mergeUtil) deploymentTemplateServiceImpl := deploymentTemplate.NewDeploymentTemplateServiceImpl(sugaredLogger, chartRefServiceImpl, chartTemplateServiceImpl, chartRepositoryImpl) appListingRepositoryQueryBuilder := helper.NewAppListingRepositoryQueryBuilder(sugaredLogger) appWorkflowRepositoryImpl := appWorkflow.NewAppWorkflowRepositoryImpl(sugaredLogger, db) @@ -551,34 +579,30 @@ func InitializeApp() (*App, error) { appListingViewBuilderImpl := app2.NewAppListingViewBuilderImpl(sugaredLogger) linkoutsRepositoryImpl := repository2.NewLinkoutsRepositoryImpl(sugaredLogger, db) ciTemplateOverrideRepositoryImpl := pipelineConfig.NewCiTemplateOverrideRepositoryImpl(db, sugaredLogger) - ciPipelineConfigReadServiceImpl := read9.NewCiPipelineConfigReadServiceImpl(sugaredLogger, ciPipelineRepositoryImpl, ciTemplateOverrideRepositoryImpl) + ciPipelineConfigReadServiceImpl := read10.NewCiPipelineConfigReadServiceImpl(sugaredLogger, ciPipelineRepositoryImpl, ciTemplateOverrideRepositoryImpl) dockerRegistryIpsConfigServiceImpl := dockerRegistry.NewDockerRegistryIpsConfigServiceImpl(sugaredLogger, dockerRegistryIpsConfigRepositoryImpl, k8sServiceImpl, dockerArtifactStoreRepositoryImpl, clusterReadServiceImpl, ciPipelineConfigReadServiceImpl) - appLevelMetricsRepositoryImpl := repository13.NewAppLevelMetricsRepositoryImpl(db, sugaredLogger) - envLevelAppMetricsRepositoryImpl := repository13.NewEnvLevelAppMetricsRepositoryImpl(db, sugaredLogger) + appLevelMetricsRepositoryImpl := repository16.NewAppLevelMetricsRepositoryImpl(db, sugaredLogger) + envLevelAppMetricsRepositoryImpl := repository16.NewEnvLevelAppMetricsRepositoryImpl(db, sugaredLogger) deployedAppMetricsServiceImpl := deployedAppMetrics.NewDeployedAppMetricsServiceImpl(sugaredLogger, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, chartRefServiceImpl) - appListingServiceImpl := app2.NewAppListingServiceImpl(sugaredLogger, appListingRepositoryImpl, applicationServiceClientImpl, appRepositoryImpl, appListingViewBuilderImpl, pipelineRepositoryImpl, linkoutsRepositoryImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, environmentRepositoryImpl, chartRepositoryImpl, ciPipelineRepositoryImpl, dockerRegistryIpsConfigServiceImpl, userRepositoryImpl, deployedAppMetricsServiceImpl, ciArtifactRepositoryImpl, envConfigOverrideReadServiceImpl, ciPipelineConfigReadServiceImpl) - appServiceImpl := app2.NewAppService(pipelineOverrideRepositoryImpl, mergeUtil, sugaredLogger, pipelineRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, applicationServiceClientImpl, appRepositoryImpl, configMapRepositoryImpl, chartRepositoryImpl, cdWorkflowRepositoryImpl, commonServiceImpl, chartTemplateServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceConfig, appStatusServiceImpl, installedAppReadServiceImpl, installedAppVersionHistoryRepositoryImpl, scopedVariableCMCSManagerImpl, acdConfig, gitOpsConfigReadServiceImpl, gitOperationServiceImpl, deploymentTemplateServiceImpl, appListingServiceImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) - globalCMCSRepositoryImpl := repository2.NewGlobalCMCSRepositoryImpl(sugaredLogger, db) - globalCMCSServiceImpl := pipeline.NewGlobalCMCSServiceImpl(sugaredLogger, globalCMCSRepositoryImpl) - argoWorkflowExecutorImpl := executors.NewArgoWorkflowExecutorImpl(sugaredLogger) - systemWorkflowExecutorImpl := executors.NewSystemWorkflowExecutorImpl(sugaredLogger, k8sServiceImpl) - infraConfigRepositoryImpl := repository14.NewInfraProfileRepositoryImpl(db, transactionUtilImpl) - unitsUnits := units.NewUnits() - infraConfigServiceImpl, err := service2.NewInfraConfigServiceImpl(sugaredLogger, infraConfigRepositoryImpl, appServiceImpl, unitsUnits) + appListingServiceImpl := app2.NewAppListingServiceImpl(sugaredLogger, appListingRepositoryImpl, appRepositoryImpl, appListingViewBuilderImpl, pipelineRepositoryImpl, linkoutsRepositoryImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, environmentRepositoryImpl, chartRepositoryImpl, ciPipelineRepositoryImpl, dockerRegistryIpsConfigServiceImpl, userRepositoryImpl, deployedAppMetricsServiceImpl, ciArtifactRepositoryImpl, envConfigOverrideReadServiceImpl, ciPipelineConfigReadServiceImpl) + appServiceImpl := app2.NewAppService(pipelineOverrideRepositoryImpl, utilMergeUtil, sugaredLogger, pipelineRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, appRepositoryImpl, configMapRepositoryImpl, chartRepositoryImpl, cdWorkflowRepositoryImpl, commonServiceImpl, chartTemplateServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceConfig, appStatusServiceImpl, installedAppReadServiceImpl, installedAppVersionHistoryRepositoryImpl, scopedVariableCMCSManagerImpl, acdConfig, gitOpsConfigReadServiceImpl, gitOperationServiceImpl, deploymentTemplateServiceImpl, appListingServiceImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) + scopedVariableManagerImpl, err := variables.NewScopedVariableManagerImpl(sugaredLogger, scopedVariableServiceImpl, variableEntityMappingServiceImpl, variableSnapshotHistoryServiceImpl, variableTemplateParserImpl) if err != nil { return nil, err } - infraProviderImpl := infraProviders.NewInfraProviderImpl(sugaredLogger, infraConfigServiceImpl) - workflowServiceImpl, err := pipeline.NewWorkflowServiceImpl(sugaredLogger, environmentRepositoryImpl, ciCdConfig, appServiceImpl, globalCMCSServiceImpl, argoWorkflowExecutorImpl, k8sServiceImpl, systemWorkflowExecutorImpl, k8sCommonServiceImpl, infraProviderImpl) + infraConfigClientImpl := config4.NewInfraConfigClient(sugaredLogger, scopedVariableManagerImpl, configReadServiceImpl) + infraConfigServiceImpl, err := service2.NewInfraConfigServiceImpl(sugaredLogger, infraConfigRepositoryImpl, appServiceImpl, devtronResourceSearchableKeyServiceImpl, qualifierMappingServiceImpl, attributesServiceImpl, infraConfigClientImpl, environmentVariables) if err != nil { return nil, err } - pipelineStageRepositoryImpl := repository15.NewPipelineStageRepository(sugaredLogger, db) - globalPluginRepositoryImpl := repository16.NewGlobalPluginRepository(sugaredLogger, db) - scopedVariableManagerImpl, err := variables.NewScopedVariableManagerImpl(sugaredLogger, scopedVariableServiceImpl, variableEntityMappingServiceImpl, variableSnapshotHistoryServiceImpl, variableTemplateParserImpl) + ciInfraGetter := ci.NewCiInfraGetter(sugaredLogger, infraConfigServiceImpl, infraConfigAuditServiceImpl) + infraProviderImpl := infraProviders.NewInfraProviderImpl(sugaredLogger, infraGetter, ciInfraGetter) + workflowServiceImpl, err := pipeline.NewWorkflowServiceImpl(sugaredLogger, environmentRepositoryImpl, ciCdConfig, configReadServiceImpl, globalCMCSServiceImpl, argoWorkflowExecutorImpl, k8sServiceImpl, systemWorkflowExecutorImpl, k8sCommonServiceImpl, infraProviderImpl) if err != nil { return nil, err } + pipelineStageRepositoryImpl := repository17.NewPipelineStageRepository(sugaredLogger, db) + globalPluginRepositoryImpl := repository18.NewGlobalPluginRepository(sugaredLogger, db) globalPluginServiceImpl := plugin.NewGlobalPluginService(sugaredLogger, globalPluginRepositoryImpl, pipelineStageRepositoryImpl, userServiceImpl) pipelineStageServiceImpl := pipeline.NewPipelineStageService(sugaredLogger, pipelineStageRepositoryImpl, globalPluginRepositoryImpl, pipelineRepositoryImpl, scopedVariableManagerImpl, globalPluginServiceImpl) ciTemplateRepositoryImpl := pipelineConfig.NewCiTemplateRepositoryImpl(db, sugaredLogger) @@ -589,8 +613,8 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - materialRepositoryImpl := repository17.NewMaterialRepositoryImpl(db) - gitMaterialReadServiceImpl := read10.NewGitMaterialReadServiceImpl(sugaredLogger, materialRepositoryImpl) + materialRepositoryImpl := repository19.NewMaterialRepositoryImpl(db) + gitMaterialReadServiceImpl := read11.NewGitMaterialReadServiceImpl(sugaredLogger, materialRepositoryImpl) appCrudOperationServiceImpl := app2.NewAppCrudOperationServiceImpl(appLabelRepositoryImpl, sugaredLogger, appRepositoryImpl, userRepositoryImpl, installedAppRepositoryImpl, genericNoteServiceImpl, installedAppDBServiceImpl, crudOperationServiceConfig, dbMigrationServiceImpl, gitMaterialReadServiceImpl) imageTagRepositoryImpl := repository2.NewImageTagRepository(db, sugaredLogger) customTagServiceImpl := pipeline.NewCustomTagService(sugaredLogger, imageTagRepositoryImpl) @@ -603,22 +627,22 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - prePostCdScriptHistoryRepositoryImpl := repository18.NewPrePostCdScriptHistoryRepositoryImpl(sugaredLogger, db) - configMapHistoryRepositoryImpl := repository18.NewConfigMapHistoryRepositoryImpl(sugaredLogger, db, transactionUtilImpl) + prePostCdScriptHistoryRepositoryImpl := repository20.NewPrePostCdScriptHistoryRepositoryImpl(sugaredLogger, db) + configMapHistoryRepositoryImpl := repository20.NewConfigMapHistoryRepositoryImpl(sugaredLogger, db, transactionUtilImpl) configMapHistoryServiceImpl := configMapAndSecret.NewConfigMapHistoryServiceImpl(sugaredLogger, configMapHistoryRepositoryImpl, pipelineRepositoryImpl, configMapRepositoryImpl, userServiceImpl, scopedVariableCMCSManagerImpl) prePostCdScriptHistoryServiceImpl := history.NewPrePostCdScriptHistoryServiceImpl(sugaredLogger, prePostCdScriptHistoryRepositoryImpl, configMapRepositoryImpl, configMapHistoryServiceImpl) - gitMaterialHistoryRepositoryImpl := repository18.NewGitMaterialHistoryRepositoyImpl(db) + gitMaterialHistoryRepositoryImpl := repository20.NewGitMaterialHistoryRepositoyImpl(db) gitMaterialHistoryServiceImpl := history.NewGitMaterialHistoryServiceImpl(gitMaterialHistoryRepositoryImpl, sugaredLogger) - ciPipelineHistoryRepositoryImpl := repository18.NewCiPipelineHistoryRepositoryImpl(db, sugaredLogger) + ciPipelineHistoryRepositoryImpl := repository20.NewCiPipelineHistoryRepositoryImpl(db, sugaredLogger) ciPipelineHistoryServiceImpl := history.NewCiPipelineHistoryServiceImpl(ciPipelineHistoryRepositoryImpl, sugaredLogger, ciPipelineRepositoryImpl) ciBuildConfigRepositoryImpl := pipelineConfig.NewCiBuildConfigRepositoryImpl(db, sugaredLogger) ciBuildConfigServiceImpl := pipeline.NewCiBuildConfigServiceImpl(sugaredLogger, ciBuildConfigRepositoryImpl) ciTemplateServiceImpl := pipeline.NewCiTemplateServiceImpl(sugaredLogger, ciBuildConfigServiceImpl, ciTemplateRepositoryImpl, ciTemplateOverrideRepositoryImpl) pipelineConfigRepositoryImpl := chartConfig.NewPipelineConfigRepository(db) - configMapServiceImpl := pipeline.NewConfigMapServiceImpl(chartRepositoryImpl, sugaredLogger, chartRepoRepositoryImpl, utilMergeUtil, pipelineConfigRepositoryImpl, configMapRepositoryImpl, envConfigOverrideRepositoryImpl, commonServiceImpl, appRepositoryImpl, configMapHistoryServiceImpl, environmentRepositoryImpl, scopedVariableCMCSManagerImpl) - deploymentTemplateHistoryRepositoryImpl := repository18.NewDeploymentTemplateHistoryRepositoryImpl(sugaredLogger, db) + configMapServiceImpl := pipeline.NewConfigMapServiceImpl(chartRepositoryImpl, sugaredLogger, chartRepoRepositoryImpl, mergeUtil, pipelineConfigRepositoryImpl, configMapRepositoryImpl, envConfigOverrideRepositoryImpl, commonServiceImpl, appRepositoryImpl, configMapHistoryServiceImpl, environmentRepositoryImpl, scopedVariableCMCSManagerImpl) + deploymentTemplateHistoryRepositoryImpl := repository20.NewDeploymentTemplateHistoryRepositoryImpl(sugaredLogger, db) deploymentTemplateHistoryServiceImpl := deploymentTemplate.NewDeploymentTemplateHistoryServiceImpl(sugaredLogger, deploymentTemplateHistoryRepositoryImpl, pipelineRepositoryImpl, chartRepositoryImpl, userServiceImpl, cdWorkflowRepositoryImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, chartRefServiceImpl) - chartServiceImpl := chart.NewChartServiceImpl(chartRepositoryImpl, sugaredLogger, chartTemplateServiceImpl, chartRepoRepositoryImpl, appRepositoryImpl, utilMergeUtil, envConfigOverrideRepositoryImpl, pipelineConfigRepositoryImpl, environmentRepositoryImpl, deploymentTemplateHistoryServiceImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, chartRefServiceImpl, gitOpsConfigReadServiceImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) + chartServiceImpl := chart.NewChartServiceImpl(chartRepositoryImpl, sugaredLogger, chartTemplateServiceImpl, chartRepoRepositoryImpl, appRepositoryImpl, mergeUtil, envConfigOverrideRepositoryImpl, pipelineConfigRepositoryImpl, environmentRepositoryImpl, deploymentTemplateHistoryServiceImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, chartRefServiceImpl, gitOpsConfigReadServiceImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) ciCdPipelineOrchestratorImpl := pipeline.NewCiCdPipelineOrchestrator(appRepositoryImpl, sugaredLogger, materialRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, ciPipelineMaterialRepositoryImpl, cdWorkflowRepositoryImpl, clientImpl, ciCdConfig, appWorkflowRepositoryImpl, environmentRepositoryImpl, attributesServiceImpl, appCrudOperationServiceImpl, userAuthServiceImpl, prePostCdScriptHistoryServiceImpl, pipelineStageServiceImpl, gitMaterialHistoryServiceImpl, ciPipelineHistoryServiceImpl, ciTemplateReadServiceImpl, ciTemplateServiceImpl, dockerArtifactStoreRepositoryImpl, ciArtifactRepositoryImpl, configMapServiceImpl, customTagServiceImpl, genericNoteServiceImpl, chartServiceImpl, transactionUtilImpl, gitOpsConfigReadServiceImpl, deploymentConfigServiceImpl) ciServiceImpl := pipeline.NewCiServiceImpl(sugaredLogger, workflowServiceImpl, ciPipelineMaterialRepositoryImpl, ciWorkflowRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, ciPipelineRepositoryImpl, ciArtifactRepositoryImpl, pipelineStageServiceImpl, userServiceImpl, ciTemplateReadServiceImpl, appCrudOperationServiceImpl, environmentRepositoryImpl, appRepositoryImpl, scopedVariableManagerImpl, customTagServiceImpl, pluginInputVariableParserImpl, globalPluginServiceImpl, infraProviderImpl, ciCdPipelineOrchestratorImpl, attributesServiceImpl) ciLogServiceImpl, err := pipeline.NewCiLogServiceImpl(sugaredLogger, ciServiceImpl, k8sServiceImpl) @@ -628,37 +652,34 @@ func InitializeApp() (*App, error) { resourceGroupRepositoryImpl := resourceGroup.NewResourceGroupRepositoryImpl(db) resourceGroupMappingRepositoryImpl := resourceGroup.NewResourceGroupMappingRepositoryImpl(db) resourceGroupServiceImpl := resourceGroup2.NewResourceGroupServiceImpl(sugaredLogger, resourceGroupRepositoryImpl, resourceGroupMappingRepositoryImpl, enforcerUtilImpl, devtronResourceSearchableKeyServiceImpl, appStatusRepositoryImpl) - imageTaggingRepositoryImpl := repository19.NewImageTaggingRepositoryImpl(db, transactionUtilImpl) - imageTaggingReadServiceImpl, err := read11.NewImageTaggingReadServiceImpl(imageTaggingRepositoryImpl, sugaredLogger) + imageTaggingRepositoryImpl := repository21.NewImageTaggingRepositoryImpl(db, transactionUtilImpl) + imageTaggingReadServiceImpl, err := read12.NewImageTaggingReadServiceImpl(imageTaggingRepositoryImpl, sugaredLogger) if err != nil { return nil, err } imageTaggingServiceImpl := imageTagging.NewImageTaggingServiceImpl(imageTaggingRepositoryImpl, imageTaggingReadServiceImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, sugaredLogger) blobStorageConfigServiceImpl := pipeline.NewBlobStorageConfigServiceImpl(sugaredLogger, k8sServiceImpl, ciCdConfig) ciHandlerImpl := pipeline.NewCiHandlerImpl(sugaredLogger, ciServiceImpl, ciPipelineMaterialRepositoryImpl, clientImpl, ciWorkflowRepositoryImpl, workflowServiceImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, userServiceImpl, eventRESTClientImpl, eventSimpleFactoryImpl, ciPipelineRepositoryImpl, appListingRepositoryImpl, k8sServiceImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, environmentRepositoryImpl, imageTaggingServiceImpl, k8sCommonServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl, appWorkflowRepositoryImpl, customTagServiceImpl, environmentServiceImpl) - gitWebhookRepositoryImpl := repository20.NewGitWebhookRepositoryImpl(db) + gitWebhookRepositoryImpl := repository22.NewGitWebhookRepositoryImpl(db) gitWebhookServiceImpl := gitWebhook.NewGitWebhookServiceImpl(sugaredLogger, ciHandlerImpl, gitWebhookRepositoryImpl) gitWebhookRestHandlerImpl := restHandler.NewGitWebhookRestHandlerImpl(sugaredLogger, gitWebhookServiceImpl) ecrConfig, err := pipeline.GetEcrConfig() if err != nil { return nil, err } - ciTemplateHistoryRepositoryImpl := repository18.NewCiTemplateHistoryRepositoryImpl(db, sugaredLogger) + ciTemplateHistoryRepositoryImpl := repository20.NewCiTemplateHistoryRepositoryImpl(db, sugaredLogger) ciTemplateHistoryServiceImpl := history.NewCiTemplateHistoryServiceImpl(ciTemplateHistoryRepositoryImpl, sugaredLogger) buildPipelineSwitchServiceImpl := pipeline.NewBuildPipelineSwitchServiceImpl(sugaredLogger, ciPipelineConfigReadServiceImpl, ciPipelineRepositoryImpl, ciCdPipelineOrchestratorImpl, pipelineRepositoryImpl, ciWorkflowRepositoryImpl, appWorkflowRepositoryImpl, ciPipelineHistoryServiceImpl, ciTemplateOverrideRepositoryImpl, ciPipelineMaterialRepositoryImpl) ciPipelineConfigServiceImpl := pipeline.NewCiPipelineConfigServiceImpl(sugaredLogger, ciCdPipelineOrchestratorImpl, dockerArtifactStoreRepositoryImpl, gitMaterialReadServiceImpl, appRepositoryImpl, pipelineRepositoryImpl, ciPipelineConfigReadServiceImpl, ciPipelineRepositoryImpl, ecrConfig, appWorkflowRepositoryImpl, ciCdConfig, attributesServiceImpl, pipelineStageServiceImpl, ciPipelineMaterialRepositoryImpl, ciTemplateServiceImpl, ciTemplateReadServiceImpl, ciTemplateOverrideRepositoryImpl, ciTemplateHistoryServiceImpl, enforcerUtilImpl, ciWorkflowRepositoryImpl, resourceGroupServiceImpl, customTagServiceImpl, cdWorkflowRepositoryImpl, buildPipelineSwitchServiceImpl, pipelineStageRepositoryImpl, globalPluginRepositoryImpl) ciMaterialConfigServiceImpl := pipeline.NewCiMaterialConfigServiceImpl(sugaredLogger, materialRepositoryImpl, ciTemplateReadServiceImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, gitMaterialHistoryServiceImpl, pipelineRepositoryImpl, ciPipelineMaterialRepositoryImpl, transactionUtilImpl, gitMaterialReadServiceImpl) deploymentGroupRepositoryImpl := repository2.NewDeploymentGroupRepositoryImpl(sugaredLogger, db) - pipelineStrategyHistoryRepositoryImpl := repository18.NewPipelineStrategyHistoryRepositoryImpl(sugaredLogger, db) + pipelineStrategyHistoryRepositoryImpl := repository20.NewPipelineStrategyHistoryRepositoryImpl(sugaredLogger, db) pipelineStrategyHistoryServiceImpl := history.NewPipelineStrategyHistoryServiceImpl(sugaredLogger, pipelineStrategyHistoryRepositoryImpl, userServiceImpl) propertiesConfigServiceImpl := pipeline.NewPropertiesConfigServiceImpl(sugaredLogger, envConfigOverrideRepositoryImpl, chartRepositoryImpl, environmentRepositoryImpl, deploymentTemplateHistoryServiceImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, envConfigOverrideReadServiceImpl) - repositoryServiceClientImpl := repository21.NewServiceClientImpl(sugaredLogger, argoCDConnectionManagerImpl) - runnable := asyncProvider.NewAsyncRunnable(sugaredLogger) - argoClientWrapperServiceImpl := argocdServer.NewArgoClientWrapperServiceImpl(sugaredLogger, applicationServiceClientImpl, acdConfig, repositoryServiceClientImpl, gitOpsConfigReadServiceImpl, gitOperationServiceImpl, runnable) imageDigestPolicyServiceImpl := imageDigestPolicy.NewImageDigestPolicyServiceImpl(sugaredLogger, qualifierMappingServiceImpl, devtronResourceSearchableKeyServiceImpl) pipelineConfigEventPublishServiceImpl := out.NewPipelineConfigEventPublishServiceImpl(sugaredLogger, pubSubClientServiceImpl) deploymentTypeOverrideServiceImpl := providerConfig.NewDeploymentTypeOverrideServiceImpl(sugaredLogger, environmentVariables, attributesServiceImpl) - 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, applicationServiceClientImpl, customTagServiceImpl, ciPipelineConfigServiceImpl, buildPipelineSwitchServiceImpl, argoClientWrapperServiceImpl, deployedAppMetricsServiceImpl, gitOpsConfigReadServiceImpl, gitOperationServiceImpl, chartServiceImpl, imageDigestPolicyServiceImpl, pipelineConfigEventPublishServiceImpl, deploymentTypeOverrideServiceImpl, deploymentConfigServiceImpl) + 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, gitOperationServiceImpl, chartServiceImpl, imageDigestPolicyServiceImpl, pipelineConfigEventPublishServiceImpl, deploymentTypeOverrideServiceImpl, deploymentConfigServiceImpl) 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) @@ -676,7 +697,7 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - appDeploymentTypeChangeManagerImpl := pipeline.NewAppDeploymentTypeChangeManagerImpl(sugaredLogger, pipelineRepositoryImpl, appServiceImpl, appStatusRepositoryImpl, helmAppServiceImpl, applicationServiceClientImpl, appArtifactManagerImpl, cdPipelineConfigServiceImpl, gitOpsConfigReadServiceImpl, chartServiceImpl, workflowEventPublishServiceImpl, deploymentConfigServiceImpl) + appDeploymentTypeChangeManagerImpl := pipeline.NewAppDeploymentTypeChangeManagerImpl(sugaredLogger, pipelineRepositoryImpl, appServiceImpl, appStatusRepositoryImpl, helmAppServiceImpl, appArtifactManagerImpl, cdPipelineConfigServiceImpl, gitOpsConfigReadServiceImpl, chartServiceImpl, workflowEventPublishServiceImpl, deploymentConfigServiceImpl) 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) @@ -688,32 +709,32 @@ func InitializeApp() (*App, error) { appCloneServiceImpl := appClone.NewAppCloneServiceImpl(sugaredLogger, pipelineBuilderImpl, attributesServiceImpl, chartServiceImpl, configMapServiceImpl, appWorkflowServiceImpl, appListingServiceImpl, propertiesConfigServiceImpl, pipelineStageServiceImpl, ciTemplateReadServiceImpl, appRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, ciPipelineConfigServiceImpl, gitOpsConfigReadServiceImpl) 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, mergeUtil, deploymentTemplateHistoryReadServiceImpl) + generateManifestDeploymentTemplateServiceImpl, err := generateManifest.NewDeploymentTemplateServiceImpl(sugaredLogger, chartServiceImpl, appListingServiceImpl, deploymentTemplateRepositoryImpl, helmAppReadServiceImpl, chartTemplateServiceImpl, helmAppClientImpl, k8sServiceImpl, propertiesConfigServiceImpl, environmentRepositoryImpl, appRepositoryImpl, scopedVariableManagerImpl, chartRefServiceImpl, pipelineOverrideRepositoryImpl, chartRepositoryImpl, pipelineRepositoryImpl, utilMergeUtil, deploymentTemplateHistoryReadServiceImpl) if err != nil { return nil, err } - cvePolicyRepositoryImpl := repository9.NewPolicyRepositoryImpl(db, sugaredLogger) - imageScanResultRepositoryImpl := repository9.NewImageScanResultRepositoryImpl(db, sugaredLogger) - imageScanDeployInfoRepositoryImpl := repository9.NewImageScanDeployInfoRepositoryImpl(db, sugaredLogger) - imageScanObjectMetaRepositoryImpl := repository9.NewImageScanObjectMetaRepositoryImpl(db, sugaredLogger) - imageScanHistoryRepositoryImpl := repository9.NewImageScanHistoryRepositoryImpl(db, sugaredLogger) - imageScanHistoryReadServiceImpl := read12.NewImageScanHistoryReadService(sugaredLogger, imageScanHistoryRepositoryImpl) - cveStoreRepositoryImpl := repository9.NewCveStoreRepositoryImpl(db, sugaredLogger) + cvePolicyRepositoryImpl := repository23.NewPolicyRepositoryImpl(db, sugaredLogger) + imageScanResultRepositoryImpl := repository23.NewImageScanResultRepositoryImpl(db, sugaredLogger) + imageScanDeployInfoRepositoryImpl := repository23.NewImageScanDeployInfoRepositoryImpl(db, sugaredLogger) + imageScanObjectMetaRepositoryImpl := repository23.NewImageScanObjectMetaRepositoryImpl(db, sugaredLogger) + imageScanHistoryRepositoryImpl := repository23.NewImageScanHistoryRepositoryImpl(db, sugaredLogger) + imageScanHistoryReadServiceImpl := read13.NewImageScanHistoryReadService(sugaredLogger, imageScanHistoryRepositoryImpl) + cveStoreRepositoryImpl := repository23.NewCveStoreRepositoryImpl(db, sugaredLogger) policyServiceImpl := imageScanning.NewPolicyServiceImpl(environmentServiceImpl, sugaredLogger, appRepositoryImpl, pipelineOverrideRepositoryImpl, cvePolicyRepositoryImpl, clusterServiceImplExtended, pipelineRepositoryImpl, imageScanResultRepositoryImpl, imageScanDeployInfoRepositoryImpl, imageScanObjectMetaRepositoryImpl, httpClient, ciArtifactRepositoryImpl, ciCdConfig, imageScanHistoryReadServiceImpl, cveStoreRepositoryImpl, ciTemplateRepositoryImpl, clusterReadServiceImpl, transactionUtilImpl) - imageScanResultReadServiceImpl := read12.NewImageScanResultReadServiceImpl(sugaredLogger, imageScanResultRepositoryImpl) + imageScanResultReadServiceImpl := read13.NewImageScanResultReadServiceImpl(sugaredLogger, imageScanResultRepositoryImpl) pipelineConfigRestHandlerImpl := configure.NewPipelineRestHandlerImpl(pipelineBuilderImpl, sugaredLogger, deploymentTemplateValidationServiceImpl, chartServiceImpl, devtronAppGitOpConfigServiceImpl, propertiesConfigServiceImpl, userServiceImpl, teamServiceImpl, enforcerImpl, ciHandlerImpl, validate, clientImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, dockerRegistryConfigImpl, cdHandlerImpl, appCloneServiceImpl, generateManifestDeploymentTemplateServiceImpl, appWorkflowServiceImpl, gitMaterialReadServiceImpl, policyServiceImpl, imageScanResultReadServiceImpl, ciPipelineMaterialRepositoryImpl, imageTaggingReadServiceImpl, imageTaggingServiceImpl, ciArtifactRepositoryImpl, deployedAppMetricsServiceImpl, chartRefServiceImpl, ciCdPipelineOrchestratorImpl, gitProviderReadServiceImpl, teamReadServiceImpl) gitOpsManifestPushServiceImpl := publish.NewGitOpsManifestPushServiceImpl(sugaredLogger, pipelineStatusTimelineServiceImpl, pipelineOverrideRepositoryImpl, acdConfig, chartRefServiceImpl, gitOpsConfigReadServiceImpl, chartServiceImpl, gitOperationServiceImpl, argoClientWrapperServiceImpl, transactionUtilImpl, deploymentConfigServiceImpl, chartTemplateServiceImpl) argoK8sClientImpl := argocdServer.NewArgoK8sClientImpl(sugaredLogger, k8sServiceImpl) - manifestCreationServiceImpl := manifest.NewManifestCreationServiceImpl(sugaredLogger, dockerRegistryIpsConfigServiceImpl, chartRefServiceImpl, scopedVariableCMCSManagerImpl, k8sCommonServiceImpl, deployedAppMetricsServiceImpl, imageDigestPolicyServiceImpl, mergeUtil, appCrudOperationServiceImpl, deploymentTemplateServiceImpl, applicationServiceClientImpl, configMapHistoryRepositoryImpl, configMapRepositoryImpl, chartRepositoryImpl, envConfigOverrideRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciArtifactRepositoryImpl, pipelineOverrideRepositoryImpl, pipelineStrategyHistoryRepositoryImpl, pipelineConfigRepositoryImpl, deploymentTemplateHistoryRepositoryImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) - configMapHistoryReadServiceImpl := read13.NewConfigMapHistoryReadService(sugaredLogger, configMapHistoryRepositoryImpl, scopedVariableCMCSManagerImpl) + manifestCreationServiceImpl := manifest.NewManifestCreationServiceImpl(sugaredLogger, dockerRegistryIpsConfigServiceImpl, chartRefServiceImpl, scopedVariableCMCSManagerImpl, k8sCommonServiceImpl, deployedAppMetricsServiceImpl, imageDigestPolicyServiceImpl, utilMergeUtil, appCrudOperationServiceImpl, deploymentTemplateServiceImpl, argoClientWrapperServiceImpl, configMapHistoryRepositoryImpl, configMapRepositoryImpl, chartRepositoryImpl, envConfigOverrideRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciArtifactRepositoryImpl, pipelineOverrideRepositoryImpl, pipelineStrategyHistoryRepositoryImpl, pipelineConfigRepositoryImpl, deploymentTemplateHistoryRepositoryImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) + configMapHistoryReadServiceImpl := read14.NewConfigMapHistoryReadService(sugaredLogger, configMapHistoryRepositoryImpl, scopedVariableCMCSManagerImpl) deployedConfigurationHistoryServiceImpl := history.NewDeployedConfigurationHistoryServiceImpl(sugaredLogger, userServiceImpl, deploymentTemplateHistoryServiceImpl, pipelineStrategyHistoryServiceImpl, configMapHistoryServiceImpl, cdWorkflowRepositoryImpl, scopedVariableCMCSManagerImpl, deploymentTemplateHistoryReadServiceImpl, configMapHistoryReadServiceImpl) - userDeploymentRequestRepositoryImpl := repository22.NewUserDeploymentRequestRepositoryImpl(db, transactionUtilImpl) + userDeploymentRequestRepositoryImpl := repository24.NewUserDeploymentRequestRepositoryImpl(db, transactionUtilImpl) userDeploymentRequestServiceImpl := service3.NewUserDeploymentRequestServiceImpl(sugaredLogger, userDeploymentRequestRepositoryImpl) - imageScanDeployInfoReadServiceImpl := read12.NewImageScanDeployInfoReadService(sugaredLogger, imageScanDeployInfoRepositoryImpl) + imageScanDeployInfoReadServiceImpl := read13.NewImageScanDeployInfoReadService(sugaredLogger, imageScanDeployInfoRepositoryImpl) imageScanDeployInfoServiceImpl := imageScanning.NewImageScanDeployInfoService(sugaredLogger, imageScanDeployInfoRepositoryImpl) - manifestPushConfigRepositoryImpl := repository15.NewManifestPushConfigRepository(sugaredLogger, db) - scanToolExecutionHistoryMappingRepositoryImpl := repository9.NewScanToolExecutionHistoryMappingRepositoryImpl(db, sugaredLogger) - cdWorkflowReadServiceImpl := read14.NewCdWorkflowReadServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) + manifestPushConfigRepositoryImpl := repository17.NewManifestPushConfigRepository(sugaredLogger, db) + scanToolExecutionHistoryMappingRepositoryImpl := repository23.NewScanToolExecutionHistoryMappingRepositoryImpl(db, sugaredLogger) + cdWorkflowReadServiceImpl := read15.NewCdWorkflowReadServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) imageScanServiceImpl := imageScanning.NewImageScanServiceImpl(sugaredLogger, imageScanHistoryRepositoryImpl, imageScanResultRepositoryImpl, imageScanObjectMetaRepositoryImpl, cveStoreRepositoryImpl, imageScanDeployInfoRepositoryImpl, userServiceImpl, appRepositoryImpl, environmentServiceImpl, ciArtifactRepositoryImpl, policyServiceImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, scanToolMetadataRepositoryImpl, scanToolExecutionHistoryMappingRepositoryImpl, cvePolicyRepositoryImpl, cdWorkflowReadServiceImpl) triggerServiceImpl, err := devtronApps.NewTriggerServiceImpl(sugaredLogger, cdWorkflowCommonServiceImpl, gitOpsManifestPushServiceImpl, gitOpsConfigReadServiceImpl, argoK8sClientImpl, acdConfig, argoClientWrapperServiceImpl, pipelineStatusTimelineServiceImpl, chartTemplateServiceImpl, workflowEventPublishServiceImpl, manifestCreationServiceImpl, deployedConfigurationHistoryServiceImpl, pipelineStageServiceImpl, globalPluginServiceImpl, customTagServiceImpl, pluginInputVariableParserImpl, prePostCdScriptHistoryServiceImpl, scopedVariableCMCSManagerImpl, workflowServiceImpl, imageDigestPolicyServiceImpl, userServiceImpl, clientImpl, helmAppServiceImpl, enforcerUtilImpl, userDeploymentRequestServiceImpl, helmAppClientImpl, eventSimpleFactoryImpl, eventRESTClientImpl, environmentVariables, appRepositoryImpl, ciPipelineMaterialRepositoryImpl, imageScanHistoryReadServiceImpl, imageScanDeployInfoReadServiceImpl, imageScanDeployInfoServiceImpl, pipelineRepositoryImpl, pipelineOverrideRepositoryImpl, manifestPushConfigRepositoryImpl, chartRepositoryImpl, environmentRepositoryImpl, cdWorkflowRepositoryImpl, ciWorkflowRepositoryImpl, ciArtifactRepositoryImpl, ciTemplateReadServiceImpl, gitMaterialReadServiceImpl, appLabelRepositoryImpl, ciPipelineRepositoryImpl, appWorkflowRepositoryImpl, dockerArtifactStoreRepositoryImpl, imageScanServiceImpl, k8sServiceImpl, transactionUtilImpl, deploymentConfigServiceImpl, ciCdPipelineOrchestratorImpl, gitOperationServiceImpl, attributesServiceImpl, clusterRepositoryImpl) if err != nil { @@ -725,7 +746,7 @@ func InitializeApp() (*App, error) { pubSubClientRestHandlerImpl := restHandler.NewPubSubClientRestHandlerImpl(pubSubClientServiceImpl, sugaredLogger, ciCdConfig) webhookRouterImpl := router.NewWebhookRouterImpl(gitWebhookRestHandlerImpl, pipelineConfigRestHandlerImpl, externalCiRestHandlerImpl, pubSubClientRestHandlerImpl) userAuthHandlerImpl := user2.NewUserAuthHandlerImpl(userAuthServiceImpl, validate, sugaredLogger, enforcerImpl) - selfRegistrationRolesRepositoryImpl := repository5.NewSelfRegistrationRolesRepositoryImpl(db, sugaredLogger) + selfRegistrationRolesRepositoryImpl := repository4.NewSelfRegistrationRolesRepositoryImpl(db, sugaredLogger) userSelfRegistrationServiceImpl := user.NewUserSelfRegistrationServiceImpl(sugaredLogger, selfRegistrationRolesRepositoryImpl, userServiceImpl) userAuthOidcHelperImpl, err := authentication.NewUserAuthOidcHelperImpl(sugaredLogger, userSelfRegistrationServiceImpl, dexConfig, settings, sessionManager) if err != nil { @@ -736,9 +757,9 @@ func InitializeApp() (*App, error) { deleteServiceFullModeImpl := delete2.NewDeleteServiceFullModeImpl(sugaredLogger, gitMaterialReadServiceImpl, gitRegistryConfigImpl, ciTemplateRepositoryImpl, dockerRegistryConfigImpl, dockerArtifactStoreRepositoryImpl) gitProviderRestHandlerImpl := restHandler.NewGitProviderRestHandlerImpl(dockerRegistryConfigImpl, sugaredLogger, gitRegistryConfigImpl, userServiceImpl, validate, enforcerImpl, teamServiceImpl, deleteServiceFullModeImpl, gitProviderReadServiceImpl) gitProviderRouterImpl := router.NewGitProviderRouterImpl(gitProviderRestHandlerImpl) - gitHostRepositoryImpl := repository23.NewGitHostRepositoryImpl(db) + gitHostRepositoryImpl := repository25.NewGitHostRepositoryImpl(db) gitHostConfigImpl := gitHost.NewGitHostConfigImpl(gitHostRepositoryImpl, sugaredLogger) - gitHostReadServiceImpl := read15.NewGitHostReadServiceImpl(sugaredLogger, gitHostRepositoryImpl, attributesServiceImpl) + gitHostReadServiceImpl := read16.NewGitHostReadServiceImpl(sugaredLogger, gitHostRepositoryImpl, attributesServiceImpl) gitHostRestHandlerImpl := restHandler.NewGitHostRestHandlerImpl(sugaredLogger, gitHostConfigImpl, userServiceImpl, validate, enforcerImpl, clientImpl, gitProviderReadServiceImpl, gitHostReadServiceImpl) gitHostRouterImpl := router.NewGitHostRouterImpl(gitHostRestHandlerImpl) chartProviderServiceImpl := chartProvider.NewChartProviderServiceImpl(sugaredLogger, chartRepoRepositoryImpl, chartRepositoryServiceImpl, dockerArtifactStoreRepositoryImpl, ociRegistryConfigRepositoryImpl) @@ -766,27 +787,27 @@ func InitializeApp() (*App, error) { chartRefRouterImpl := router.NewChartRefRouterImpl(chartRefRestHandlerImpl) configMapRestHandlerImpl := restHandler.NewConfigMapRestHandlerImpl(pipelineBuilderImpl, sugaredLogger, chartServiceImpl, userServiceImpl, teamServiceImpl, enforcerImpl, pipelineRepositoryImpl, enforcerUtilImpl, configMapServiceImpl) configMapRouterImpl := router.NewConfigMapRouterImpl(configMapRestHandlerImpl) - k8sResourceHistoryRepositoryImpl := repository24.NewK8sResourceHistoryRepositoryImpl(db, sugaredLogger) + k8sResourceHistoryRepositoryImpl := repository26.NewK8sResourceHistoryRepositoryImpl(db, sugaredLogger) k8sResourceHistoryServiceImpl := kubernetesResourceAuditLogs.Newk8sResourceHistoryServiceImpl(k8sResourceHistoryRepositoryImpl, sugaredLogger, appRepositoryImpl, environmentRepositoryImpl) - ephemeralContainersRepositoryImpl := repository4.NewEphemeralContainersRepositoryImpl(db, transactionUtilImpl) - ephemeralContainerServiceImpl := cluster2.NewEphemeralContainerServiceImpl(ephemeralContainersRepositoryImpl, sugaredLogger) + ephemeralContainersRepositoryImpl := repository5.NewEphemeralContainersRepositoryImpl(db, transactionUtilImpl) + ephemeralContainerServiceImpl := cluster.NewEphemeralContainerServiceImpl(ephemeralContainersRepositoryImpl, sugaredLogger) terminalSessionHandlerImpl := terminal.NewTerminalSessionHandlerImpl(environmentServiceImpl, sugaredLogger, k8sServiceImpl, ephemeralContainerServiceImpl, argoApplicationConfigServiceImpl, clusterReadServiceImpl) fluxApplicationServiceImpl := fluxApplication.NewFluxApplicationServiceImpl(sugaredLogger, helmAppReadServiceImpl, clusterServiceImplExtended, helmAppClientImpl, pumpImpl) k8sApplicationServiceImpl, err := application2.NewK8sApplicationServiceImpl(sugaredLogger, clusterServiceImplExtended, pumpImpl, helmAppServiceImpl, k8sServiceImpl, acdAuthConfig, k8sResourceHistoryServiceImpl, k8sCommonServiceImpl, terminalSessionHandlerImpl, ephemeralContainerServiceImpl, ephemeralContainersRepositoryImpl, fluxApplicationServiceImpl, clusterReadServiceImpl) if err != nil { return nil, err } - argoApplicationServiceExtendedImpl := argoApplication.NewArgoApplicationServiceExtendedServiceImpl(sugaredLogger, clusterRepositoryImpl, k8sServiceImpl, helmAppClientImpl, helmAppServiceImpl, k8sApplicationServiceImpl, argoApplicationConfigServiceImpl, applicationServiceClientImpl) - installedAppResourceServiceImpl := resource.NewInstalledAppResourceServiceImpl(sugaredLogger, installedAppRepositoryImpl, appStoreApplicationVersionRepositoryImpl, applicationServiceClientImpl, acdAuthConfig, installedAppVersionHistoryRepositoryImpl, helmAppServiceImpl, helmAppReadServiceImpl, appStatusServiceImpl, k8sCommonServiceImpl, k8sApplicationServiceImpl, k8sServiceImpl, deploymentConfigServiceImpl, ociRegistryConfigRepositoryImpl, argoApplicationServiceExtendedImpl) - chartGroupEntriesRepositoryImpl := repository25.NewChartGroupEntriesRepositoryImpl(db, sugaredLogger) - chartGroupReposotoryImpl := repository25.NewChartGroupReposotoryImpl(db, sugaredLogger) - chartGroupDeploymentRepositoryImpl := repository25.NewChartGroupDeploymentRepositoryImpl(db, sugaredLogger) + argoApplicationServiceExtendedImpl := argoApplication.NewArgoApplicationServiceExtendedServiceImpl(sugaredLogger, clusterRepositoryImpl, k8sServiceImpl, helmAppClientImpl, helmAppServiceImpl, k8sApplicationServiceImpl, argoApplicationConfigServiceImpl, argoClientWrapperServiceImpl) + installedAppResourceServiceImpl := resource.NewInstalledAppResourceServiceImpl(sugaredLogger, installedAppRepositoryImpl, appStoreApplicationVersionRepositoryImpl, argoClientWrapperServiceImpl, acdAuthConfig, installedAppVersionHistoryRepositoryImpl, helmAppServiceImpl, helmAppReadServiceImpl, appStatusServiceImpl, k8sCommonServiceImpl, k8sApplicationServiceImpl, k8sServiceImpl, deploymentConfigServiceImpl, ociRegistryConfigRepositoryImpl, argoApplicationServiceExtendedImpl) + chartGroupEntriesRepositoryImpl := repository27.NewChartGroupEntriesRepositoryImpl(db, sugaredLogger) + chartGroupReposotoryImpl := repository27.NewChartGroupReposotoryImpl(db, sugaredLogger) + chartGroupDeploymentRepositoryImpl := repository27.NewChartGroupDeploymentRepositoryImpl(db, sugaredLogger) appStoreVersionValuesRepositoryImpl := appStoreValuesRepository.NewAppStoreVersionValuesRepositoryImpl(sugaredLogger, db) appStoreRepositoryImpl := appStoreDiscoverRepository.NewAppStoreRepositoryImpl(sugaredLogger, db) clusterInstalledAppsRepositoryImpl := repository3.NewClusterInstalledAppsRepositoryImpl(db, sugaredLogger) appStoreValuesServiceImpl := service4.NewAppStoreValuesServiceImpl(sugaredLogger, appStoreApplicationVersionRepositoryImpl, installedAppRepositoryImpl, installedAppReadServiceEAImpl, appStoreVersionValuesRepositoryImpl, userServiceImpl) appStoreDeploymentCommonServiceImpl := appStoreDeploymentCommon.NewAppStoreDeploymentCommonServiceImpl(sugaredLogger, appStoreApplicationVersionRepositoryImpl, chartTemplateServiceImpl, userServiceImpl, helmAppServiceImpl, installedAppDBServiceImpl) - fullModeDeploymentServiceImpl := deployment.NewFullModeDeploymentServiceImpl(sugaredLogger, applicationServiceClientImpl, argoK8sClientImpl, acdAuthConfig, chartGroupDeploymentRepositoryImpl, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appStoreDeploymentCommonServiceImpl, helmAppServiceImpl, appStatusServiceImpl, pipelineStatusTimelineServiceImpl, userServiceImpl, pipelineStatusTimelineRepositoryImpl, appStoreApplicationVersionRepositoryImpl, argoClientWrapperServiceImpl, acdConfig, gitOperationServiceImpl, gitOpsConfigReadServiceImpl, gitOpsValidationServiceImpl, environmentRepositoryImpl, deploymentConfigServiceImpl, chartTemplateServiceImpl, repositorySecretImpl) + fullModeDeploymentServiceImpl := deployment.NewFullModeDeploymentServiceImpl(sugaredLogger, argoK8sClientImpl, acdAuthConfig, chartGroupDeploymentRepositoryImpl, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appStoreDeploymentCommonServiceImpl, helmAppServiceImpl, appStatusServiceImpl, pipelineStatusTimelineServiceImpl, userServiceImpl, pipelineStatusTimelineRepositoryImpl, appStoreApplicationVersionRepositoryImpl, argoClientWrapperServiceImpl, acdConfig, gitOperationServiceImpl, gitOpsConfigReadServiceImpl, gitOpsValidationServiceImpl, environmentRepositoryImpl, deploymentConfigServiceImpl, chartTemplateServiceImpl) appStoreValidatorImpl := service5.NewAppAppStoreValidatorImpl(sugaredLogger) appStoreDeploymentDBServiceImpl := service5.NewAppStoreDeploymentDBServiceImpl(sugaredLogger, installedAppRepositoryImpl, appStoreApplicationVersionRepositoryImpl, appRepositoryImpl, environmentServiceImpl, installedAppVersionHistoryRepositoryImpl, environmentVariables, gitOpsConfigReadServiceImpl, deploymentTypeOverrideServiceImpl, fullModeDeploymentServiceImpl, appStoreValidatorImpl, installedAppDBServiceImpl, deploymentConfigServiceImpl, clusterReadServiceImpl) eaModeDeploymentServiceImpl := deployment2.NewEAModeDeploymentServiceImpl(sugaredLogger, helmAppServiceImpl, appStoreApplicationVersionRepositoryImpl, helmAppClientImpl, installedAppRepositoryImpl, ociRegistryConfigRepositoryImpl, appStoreDeploymentCommonServiceImpl, helmAppReadServiceImpl) @@ -798,13 +819,13 @@ func InitializeApp() (*App, error) { return nil, err } cdPipelineEventPublishServiceImpl := out.NewCDPipelineEventPublishServiceImpl(sugaredLogger, pubSubClientServiceImpl) - workflowStatusServiceImpl, err := status2.NewWorkflowStatusServiceImpl(sugaredLogger, workflowDagExecutorImpl, pipelineStatusTimelineServiceImpl, appServiceImpl, appStatusServiceImpl, acdConfig, appServiceConfig, pipelineStatusSyncDetailServiceImpl, argoClientWrapperServiceImpl, cdPipelineEventPublishServiceImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, installedAppRepositoryImpl, installedAppReadServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineRepositoryImpl, applicationServiceClientImpl, appListingServiceImpl, deploymentConfigServiceImpl) + workflowStatusServiceImpl, err := status2.NewWorkflowStatusServiceImpl(sugaredLogger, workflowDagExecutorImpl, pipelineStatusTimelineServiceImpl, appServiceImpl, appStatusServiceImpl, acdConfig, appServiceConfig, pipelineStatusSyncDetailServiceImpl, argoClientWrapperServiceImpl, cdPipelineEventPublishServiceImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, installedAppRepositoryImpl, installedAppReadServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineRepositoryImpl, appListingServiceImpl, deploymentConfigServiceImpl) if err != nil { return nil, err } cdApplicationStatusUpdateHandlerImpl := cron2.NewCdApplicationStatusUpdateHandlerImpl(sugaredLogger, appServiceImpl, workflowDagExecutorImpl, installedAppDBServiceImpl, appServiceConfig, pipelineStatusTimelineRepositoryImpl, eventRESTClientImpl, appListingRepositoryImpl, cdWorkflowRepositoryImpl, pipelineRepositoryImpl, installedAppVersionHistoryRepositoryImpl, installedAppReadServiceImpl, cronLoggerImpl, cdWorkflowCommonServiceImpl, workflowStatusServiceImpl) - installedAppDeploymentTypeChangeServiceImpl := deploymentTypeChange.NewInstalledAppDeploymentTypeChangeServiceImpl(sugaredLogger, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appStatusRepositoryImpl, gitOpsConfigReadServiceImpl, environmentRepositoryImpl, applicationServiceClientImpl, k8sCommonServiceImpl, k8sServiceImpl, fullModeDeploymentServiceImpl, eaModeDeploymentServiceImpl, argoClientWrapperServiceImpl, chartGroupServiceImpl, helmAppServiceImpl, clusterServiceImplExtended, clusterReadServiceImpl, appRepositoryImpl, deploymentConfigServiceImpl, argoApplicationServiceExtendedImpl) - installedAppRestHandlerImpl := appStore.NewInstalledAppRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, installedAppDBExtendedServiceImpl, installedAppResourceServiceImpl, chartGroupServiceImpl, validate, clusterServiceImplExtended, applicationServiceClientImpl, appStoreDeploymentServiceImpl, appStoreDeploymentDBServiceImpl, helmAppClientImpl, cdApplicationStatusUpdateHandlerImpl, installedAppRepositoryImpl, appCrudOperationServiceImpl, installedAppDeploymentTypeChangeServiceImpl, clusterReadServiceImpl) + installedAppDeploymentTypeChangeServiceImpl := deploymentTypeChange.NewInstalledAppDeploymentTypeChangeServiceImpl(sugaredLogger, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appStatusRepositoryImpl, gitOpsConfigReadServiceImpl, environmentRepositoryImpl, k8sCommonServiceImpl, k8sServiceImpl, fullModeDeploymentServiceImpl, eaModeDeploymentServiceImpl, argoClientWrapperServiceImpl, chartGroupServiceImpl, helmAppServiceImpl, clusterServiceImplExtended, clusterReadServiceImpl, appRepositoryImpl, deploymentConfigServiceImpl, argoApplicationServiceExtendedImpl) + installedAppRestHandlerImpl := appStore.NewInstalledAppRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, enforcerUtilImpl, enforcerUtilHelmImpl, installedAppDBExtendedServiceImpl, installedAppResourceServiceImpl, chartGroupServiceImpl, validate, clusterServiceImplExtended, appStoreDeploymentServiceImpl, appStoreDeploymentDBServiceImpl, helmAppClientImpl, cdApplicationStatusUpdateHandlerImpl, installedAppRepositoryImpl, appCrudOperationServiceImpl, installedAppDeploymentTypeChangeServiceImpl, clusterReadServiceImpl) appStoreValuesRestHandlerImpl := appStoreValues.NewAppStoreValuesRestHandlerImpl(sugaredLogger, userServiceImpl, appStoreValuesServiceImpl) appStoreValuesRouterImpl := appStoreValues.NewAppStoreValuesRouterImpl(appStoreValuesRestHandlerImpl) appStoreServiceImpl := service6.NewAppStoreServiceImpl(sugaredLogger, appStoreApplicationVersionRepositoryImpl) @@ -846,9 +867,7 @@ func InitializeApp() (*App, error) { imageScanRouterImpl := router.NewImageScanRouterImpl(imageScanRestHandlerImpl) policyRestHandlerImpl := restHandler.NewPolicyRestHandlerImpl(sugaredLogger, policyServiceImpl, userServiceImpl, userAuthServiceImpl, enforcerImpl, enforcerUtilImpl, environmentServiceImpl) policyRouterImpl := router.NewPolicyRouterImpl(policyRestHandlerImpl) - certificateServiceClientImpl := certificate.NewServiceClientImpl(sugaredLogger, argoCDConnectionManagerImpl) - serviceClientImpl2 := repository26.NewServiceClientImpl(sugaredLogger, argoCDConnectionManagerImpl) - gitOpsConfigServiceImpl := gitops.NewGitOpsConfigServiceImpl(sugaredLogger, gitOpsConfigRepositoryImpl, k8sServiceImpl, acdAuthConfig, clusterServiceImplExtended, serviceClientImpl, gitOperationServiceImpl, gitOpsConfigReadServiceImpl, gitOpsValidationServiceImpl, certificateServiceClientImpl, repositoryServiceClientImpl, serviceClientImpl2, environmentVariables, argoCDConnectionManagerImpl) + gitOpsConfigServiceImpl := gitops.NewGitOpsConfigServiceImpl(sugaredLogger, gitOpsConfigRepositoryImpl, k8sServiceImpl, acdAuthConfig, clusterServiceImplExtended, gitOperationServiceImpl, gitOpsConfigReadServiceImpl, gitOpsValidationServiceImpl, certificateServiceClientImpl, repositoryServiceClientImpl, environmentVariables, argoCDConnectionManagerImpl, argoCDConfigGetterImpl, argoClientWrapperServiceImpl, clusterReadServiceImpl) gitOpsConfigRestHandlerImpl := restHandler.NewGitOpsConfigRestHandlerImpl(sugaredLogger, gitOpsConfigServiceImpl, userServiceImpl, validate, enforcerImpl, teamServiceImpl) gitOpsConfigRouterImpl := router.NewGitOpsConfigRouterImpl(gitOpsConfigRestHandlerImpl) dashboardConfig, err := dashboard.GetConfig() @@ -893,7 +912,7 @@ func InitializeApp() (*App, error) { bulkUpdateRepositoryImpl := bulkUpdate.NewBulkUpdateRepository(db, sugaredLogger) deployedAppServiceImpl := deployedApp.NewDeployedAppServiceImpl(sugaredLogger, k8sCommonServiceImpl, triggerServiceImpl, environmentRepositoryImpl, pipelineRepositoryImpl, cdWorkflowRepositoryImpl) bulkUpdateServiceImpl := bulkAction.NewBulkUpdateServiceImpl(bulkUpdateRepositoryImpl, sugaredLogger, environmentRepositoryImpl, pipelineRepositoryImpl, appRepositoryImpl, deploymentTemplateHistoryServiceImpl, configMapHistoryServiceImpl, pipelineBuilderImpl, enforcerUtilImpl, ciHandlerImpl, ciPipelineRepositoryImpl, appWorkflowRepositoryImpl, appWorkflowServiceImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, chartRefServiceImpl, deployedAppServiceImpl, cdPipelineEventPublishServiceImpl) - bulkUpdateRestHandlerImpl := restHandler.NewBulkUpdateRestHandlerImpl(pipelineBuilderImpl, sugaredLogger, bulkUpdateServiceImpl, chartServiceImpl, propertiesConfigServiceImpl, applicationServiceClientImpl, userServiceImpl, teamServiceImpl, enforcerImpl, ciHandlerImpl, validate, clientImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, environmentServiceImpl, gitRegistryConfigImpl, dockerRegistryConfigImpl, cdHandlerImpl, appCloneServiceImpl, appWorkflowServiceImpl, materialRepositoryImpl) + bulkUpdateRestHandlerImpl := restHandler.NewBulkUpdateRestHandlerImpl(pipelineBuilderImpl, sugaredLogger, bulkUpdateServiceImpl, chartServiceImpl, propertiesConfigServiceImpl, userServiceImpl, teamServiceImpl, enforcerImpl, ciHandlerImpl, validate, clientImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, environmentServiceImpl, gitRegistryConfigImpl, dockerRegistryConfigImpl, cdHandlerImpl, appCloneServiceImpl, appWorkflowServiceImpl, materialRepositoryImpl) bulkUpdateRouterImpl := router.NewBulkUpdateRouterImpl(bulkUpdateRestHandlerImpl) webhookSecretValidatorImpl := gitWebhook.NewWebhookSecretValidatorImpl(sugaredLogger) webhookEventDataRepositoryImpl := repository2.NewWebhookEventDataRepositoryImpl(db) @@ -914,7 +933,7 @@ func InitializeApp() (*App, error) { pipelineTriggerRouterImpl := trigger2.NewPipelineTriggerRouter(pipelineTriggerRestHandlerImpl, sseSSE) webhookDataRestHandlerImpl := webhook.NewWebhookDataRestHandlerImpl(sugaredLogger, userServiceImpl, ciPipelineMaterialRepositoryImpl, enforcerUtilImpl, enforcerImpl, clientImpl, webhookEventDataConfigImpl) pipelineConfigRouterImpl := configure2.NewPipelineRouterImpl(pipelineConfigRestHandlerImpl, webhookDataRestHandlerImpl) - prePostCiScriptHistoryRepositoryImpl := repository18.NewPrePostCiScriptHistoryRepositoryImpl(sugaredLogger, db) + prePostCiScriptHistoryRepositoryImpl := repository20.NewPrePostCiScriptHistoryRepositoryImpl(sugaredLogger, db) prePostCiScriptHistoryServiceImpl := history.NewPrePostCiScriptHistoryServiceImpl(sugaredLogger, prePostCiScriptHistoryRepositoryImpl) pipelineHistoryRestHandlerImpl := history2.NewPipelineHistoryRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, pipelineStrategyHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, configMapHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, prePostCdScriptHistoryServiceImpl, enforcerUtilImpl, deployedConfigurationHistoryServiceImpl) pipelineHistoryRouterImpl := history3.NewPipelineHistoryRouterImpl(pipelineHistoryRestHandlerImpl) @@ -929,7 +948,7 @@ func InitializeApp() (*App, error) { coreAppRouterImpl := router.NewCoreAppRouterImpl(coreAppRestHandlerImpl) helmAppRestHandlerImpl := client3.NewHelmAppRestHandlerImpl(sugaredLogger, helmAppServiceImpl, enforcerImpl, clusterServiceImplExtended, enforcerUtilHelmImpl, appStoreDeploymentServiceImpl, installedAppDBServiceImpl, userServiceImpl, attributesServiceImpl, serverEnvConfigServerEnvConfig, fluxApplicationServiceImpl, argoApplicationServiceExtendedImpl) helmAppRouterImpl := client3.NewHelmAppRouterImpl(helmAppRestHandlerImpl) - argoApplicationReadServiceImpl := read16.NewArgoApplicationReadServiceImpl(sugaredLogger, clusterRepositoryImpl, k8sServiceImpl, helmAppClientImpl, helmAppServiceImpl) + argoApplicationReadServiceImpl := read17.NewArgoApplicationReadServiceImpl(sugaredLogger, clusterRepositoryImpl, k8sServiceImpl, helmAppClientImpl, helmAppServiceImpl) k8sApplicationRestHandlerImpl := application3.NewK8sApplicationRestHandlerImpl(sugaredLogger, k8sApplicationServiceImpl, pumpImpl, terminalSessionHandlerImpl, enforcerImpl, enforcerUtilHelmImpl, enforcerUtilImpl, helmAppServiceImpl, userServiceImpl, k8sCommonServiceImpl, validate, environmentVariables, fluxApplicationServiceImpl, argoApplicationReadServiceImpl) k8sApplicationRouterImpl := application3.NewK8sApplicationRouterImpl(k8sApplicationRestHandlerImpl) pProfRestHandlerImpl := restHandler.NewPProfRestHandler(userServiceImpl, enforcerImpl) @@ -1007,7 +1026,7 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - deploymentConfigurationServiceImpl, err := configDiff.NewDeploymentConfigurationServiceImpl(sugaredLogger, configMapServiceImpl, appRepositoryImpl, environmentRepositoryImpl, chartServiceImpl, generateManifestDeploymentTemplateServiceImpl, deploymentTemplateHistoryRepositoryImpl, pipelineStrategyHistoryRepositoryImpl, configMapHistoryRepositoryImpl, scopedVariableCMCSManagerImpl, configMapRepositoryImpl, pipelineDeploymentConfigServiceImpl, chartRefServiceImpl, pipelineRepositoryImpl, configMapHistoryServiceImpl, deploymentTemplateHistoryReadServiceImpl, configMapHistoryReadServiceImpl, cdWorkflowRepositoryImpl, envConfigOverrideReadServiceImpl, chartTemplateServiceImpl, helmAppClientImpl, helmAppServiceImpl, k8sServiceImpl, utilMergeUtil, helmAppReadServiceImpl) + deploymentConfigurationServiceImpl, err := configDiff.NewDeploymentConfigurationServiceImpl(sugaredLogger, configMapServiceImpl, appRepositoryImpl, environmentRepositoryImpl, chartServiceImpl, generateManifestDeploymentTemplateServiceImpl, deploymentTemplateHistoryRepositoryImpl, pipelineStrategyHistoryRepositoryImpl, configMapHistoryRepositoryImpl, scopedVariableCMCSManagerImpl, configMapRepositoryImpl, pipelineDeploymentConfigServiceImpl, chartRefServiceImpl, pipelineRepositoryImpl, configMapHistoryServiceImpl, deploymentTemplateHistoryReadServiceImpl, configMapHistoryReadServiceImpl, cdWorkflowRepositoryImpl, envConfigOverrideReadServiceImpl, chartTemplateServiceImpl, helmAppClientImpl, helmAppServiceImpl, k8sServiceImpl, mergeUtil, helmAppReadServiceImpl) if err != nil { return nil, err } @@ -1030,7 +1049,7 @@ func InitializeApp() (*App, error) { loggingMiddlewareImpl := util4.NewLoggingMiddlewareImpl(userServiceImpl) cdWorkflowServiceImpl := cd.NewCdWorkflowServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) cdWorkflowRunnerServiceImpl := cd.NewCdWorkflowRunnerServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) - cdWorkflowRunnerReadServiceImpl := read14.NewCdWorkflowRunnerReadServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) + cdWorkflowRunnerReadServiceImpl := read15.NewCdWorkflowRunnerReadServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) webhookServiceImpl := pipeline.NewWebhookServiceImpl(ciArtifactRepositoryImpl, sugaredLogger, ciPipelineRepositoryImpl, ciWorkflowRepositoryImpl, cdWorkflowCommonServiceImpl) workflowEventProcessorImpl, err := in.NewWorkflowEventProcessorImpl(sugaredLogger, pubSubClientServiceImpl, cdWorkflowServiceImpl, cdWorkflowReadServiceImpl, cdWorkflowRunnerServiceImpl, cdWorkflowRunnerReadServiceImpl, workflowDagExecutorImpl, ciHandlerImpl, cdHandlerImpl, eventSimpleFactoryImpl, eventRESTClientImpl, triggerServiceImpl, deployedAppServiceImpl, webhookServiceImpl, validate, environmentVariables, cdWorkflowCommonServiceImpl, cdPipelineConfigServiceImpl, userDeploymentRequestServiceImpl, pipelineRepositoryImpl, ciArtifactRepositoryImpl, cdWorkflowRepositoryImpl, deploymentConfigServiceImpl) if err != nil {