diff --git a/client/argocdServer/ArgoClientWrapperService.go b/client/argocdServer/ArgoClientWrapperService.go index 9b501aef1c..df3e5a0126 100644 --- a/client/argocdServer/ArgoClientWrapperService.go +++ b/client/argocdServer/ArgoClientWrapperService.go @@ -51,9 +51,9 @@ import ( ) type ACDConfig struct { - ArgoCDAutoSyncEnabled bool `env:"ARGO_AUTO_SYNC_ENABLED" envDefault:"true" description:"If enabled all argocd application will have auto sync enabled"` // will gradually switch this flag to false in enterprise - RegisterRepoMaxRetryCount int `env:"ARGO_REPO_REGISTER_RETRY_COUNT" envDefault:"3" description:"Argo app registration in argo retries on deployment"` - RegisterRepoMaxRetryDelay int `env:"ARGO_REPO_REGISTER_RETRY_DELAY" envDefault:"10" description:"Argo app registration in argo cd on deployment delay between retry"` + ArgoCDAutoSyncEnabled bool `env:"ARGO_AUTO_SYNC_ENABLED" envDefault:"true" description:"If enabled all argocd application will have auto sync enabled" example:"true" deprecated:"false"` // will gradually switch this flag to false in enterprise + RegisterRepoMaxRetryCount int `env:"ARGO_REPO_REGISTER_RETRY_COUNT" envDefault:"4" description:"Retry count for registering a GitOps repository to ArgoCD" example:"3" deprecated:"false"` + RegisterRepoMaxRetryDelay int `env:"ARGO_REPO_REGISTER_RETRY_DELAY" envDefault:"5" description:"Delay (in Seconds) between the retries for registering a GitOps repository to ArgoCD" example:"5" deprecated:"false"` } func (config *ACDConfig) IsManualSyncEnabled() bool { @@ -105,7 +105,7 @@ type ApplicationClientWrapper interface { // IsArgoAppPatchRequired decides weather the v1alpha1.ApplicationSource requires to be updated IsArgoAppPatchRequired(argoAppSpec *v1alpha1.ApplicationSource, currentGitRepoUrl, currentTargetRevision, currentChartPath string) bool - // GetGitOpsRepoName returns the GitOps repository name, configured for the argoCd app + // GetGitOpsRepoNameForApplication returns the GitOps repository name, configured for the argoCd app GetGitOpsRepoNameForApplication(ctx context.Context, appName string) (gitOpsRepoName string, err error) GetGitOpsRepoURLForApplication(ctx context.Context, appName string) (gitOpsRepoURL string, err error) @@ -127,6 +127,7 @@ type RepoCredsClientWrapper interface { 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) + CertificateClientWrapperEnt } type ClusterClientWrapper interface { @@ -147,7 +148,7 @@ type ArgoClientWrapperServiceImpl struct { repositoryService repository.ServiceClient clusterClient cluster.ServiceClient repoCredsClient repocreds2.ServiceClient - CertificateClient certificate2.ServiceClient + certificateClient certificate2.ServiceClient logger *zap.SugaredLogger ACDConfig *ACDConfig gitOpsConfigReadService config.GitOpsConfigReadService @@ -176,7 +177,7 @@ func NewArgoClientWrapperServiceImpl( repositoryService: repositoryService, clusterClient: clusterClient, repoCredsClient: repocredsClient, - CertificateClient: CertificateClient, + certificateClient: CertificateClient, logger: logger, ACDConfig: ACDConfig, gitOpsConfigReadService: gitOpsConfigReadService, @@ -521,7 +522,7 @@ func (impl *ArgoClientWrapperServiceImpl) createRepoInArgoCd(ctx context.Context } 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) + impl.logger.Errorw("error in creating argo Repository", "url", gitOpsRepoUrl, "err", err) return err } return nil @@ -530,7 +531,8 @@ func (impl *ArgoClientWrapperServiceImpl) createRepoInArgoCd(ctx context.Context // isRetryableArgoRepoCreationError returns whether to retry or not, based on the error returned from callback func // In createRepoInArgoCd, we will retry only if the error matches to bean.ArgoRepoSyncDelayErr func (impl *ArgoClientWrapperServiceImpl) isRetryableArgoRepoCreationError(argoCdErr error) bool { - return strings.Contains(argoCdErr.Error(), bean.ArgoRepoSyncDelayErr) + return strings.Contains(argoCdErr.Error(), bean.ArgoRepoSyncDelayErr) || + strings.Contains(argoCdErr.Error(), bean.ArgoRepoSyncDelayErrOld) } // handleArgoRepoCreationError - manages the error thrown while performing createRepoInArgoCd @@ -543,15 +545,18 @@ func (impl *ArgoClientWrapperServiceImpl) handleArgoRepoCreationError(ctx contex } } if isEmptyRepoError { - // - found empty repository, create some file in repository + impl.logger.Infow("handling for empty repo", "url", gitOpsRepoUrl) + // - found empty repository (there is no origin/HEAD) + // - create new commit on HEAD (default branch) with a README file + // - then register the repository in ArgoCD gitOpsRepoName := impl.gitOpsConfigReadService.GetGitOpsRepoNameFromUrl(gitOpsRepoUrl) - err := impl.gitOperationService.CreateReadmeInGitRepo(ctx, gitOpsRepoName, targetRevision, userId) + err := impl.gitOperationService.CreateFirstCommitOnHead(ctx, gitOpsRepoName, userId) if err != nil { impl.logger.Errorw("error in creating file in git repo", "err", err) return err } } - // try to register with after creating readme file + // try to register with after commiting a file to origin/HEAD return impl.createRepoInArgoCd(ctx, grpcConfig, gitOpsRepoUrl) } @@ -586,7 +591,7 @@ func (impl *ArgoClientWrapperServiceImpl) CreateCertificate(ctx context.Context, if err != nil { return nil, err } - return impl.CertificateClient.CreateCertificate(ctx, grpcConfig, query) + return impl.certificateClient.CreateCertificate(ctx, grpcConfig, query) } func (impl *ArgoClientWrapperServiceImpl) DeleteCertificate(ctx context.Context, query *certificate.RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { @@ -594,5 +599,5 @@ func (impl *ArgoClientWrapperServiceImpl) DeleteCertificate(ctx context.Context, if err != nil { return nil, err } - return impl.CertificateClient.DeleteCertificate(ctx, grpcConfig, query, opts...) + return impl.certificateClient.DeleteCertificate(ctx, grpcConfig, query, opts...) } diff --git a/client/argocdServer/ArgoClientWrapperService_ent.go b/client/argocdServer/ArgoClientWrapperService_ent.go new file mode 100644 index 0000000000..064eaa4115 --- /dev/null +++ b/client/argocdServer/ArgoClientWrapperService_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 argocdServer + +type CertificateClientWrapperEnt interface { +} diff --git a/client/argocdServer/bean/bean.go b/client/argocdServer/bean/bean.go index 168ab6694a..aa3b20209e 100644 --- a/client/argocdServer/bean/bean.go +++ b/client/argocdServer/bean/bean.go @@ -46,7 +46,9 @@ const RegisterRepoMaxRetryCount = 3 var EmptyRepoErrorList = []string{"failed to get index: 404 Not Found", "remote repository is empty"} // ArgoRepoSyncDelayErr - This error occurs inconsistently; ArgoCD requires 80-120s after last commit for create repository operation -const ArgoRepoSyncDelayErr = "Unable to resolve 'HEAD' to a commit SHA" +// Error message reference: https://github.com/argoproj/argo-cd/blob/master/util/git/client.go#L718 +const ArgoRepoSyncDelayErr = "unable to resolve 'HEAD' to a commit SHA" // argocd version <= v2.13.0 +const ArgoRepoSyncDelayErrOld = "Unable to resolve 'HEAD' to a commit SHA" // argocd version > v2.13.0 const ( Degraded = "Degraded" diff --git a/client/argocdServer/k8sClient.go b/client/argocdServer/k8sClient.go index 6471296fcb..c96717f243 100644 --- a/client/argocdServer/k8sClient.go +++ b/client/argocdServer/k8sClient.go @@ -227,7 +227,6 @@ func (impl ArgoK8sClientImpl) DeleteArgoApplication(ctx context.Context, k8sConf patchType := types.MergePatchType patchJSON := "" - //TODO: ayush test cascade delete if cascadeDelete { patchJSON = `{"metadata": {"finalizers": ["resources-finalizer.argocd.argoproj.io"]}}` } else { diff --git a/env_gen.json b/env_gen.json index e137f7d5b3..5b9da56042 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":"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)","Example":"","Deprecated":"false"},{"Env":"CD_HELM_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time to check the pipeline status ","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time for CD pipeline status","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_TIMEOUT_DURATION","EnvType":"string","EnvValue":"20","EnvDescription":"Timeout for CD pipeline to get healthy","Example":"","Deprecated":"false"},{"Env":"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS","EnvType":"int","EnvValue":"12","EnvDescription":"This flag is used to fetch the deployment status of the application. It retrieves the status of deployments that occurred between 12 hours and 10 minutes prior to the current time. It fetches non-terminal statuses.","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"1","EnvDescription":"Context timeout for gitops concurrent async deployments","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"6","EnvDescription":"Context timeout for no gitops concurrent async deployments","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CD_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_MIGRATE_ARGOCD_APPLICATION_ENABLE","EnvType":"bool","EnvValue":"false","EnvDescription":"enable migration of external argocd application to devtron pipeline","Example":"","Deprecated":"false"},{"Env":"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"eligible time for checking helm app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle.","Example":"","Deprecated":"false"},{"Env":"IS_INTERNAL_USE","EnvType":"bool","EnvValue":"true","EnvDescription":"If enabled then cd pipeline and helm apps will not need the deployment app type mandatorily. Couple this flag with HIDE_GITOPS_OR_HELM_OPTION (in Dashborad) and if gitops is configured and allowed for the env, pipeline/ helm app will gitops else no-gitops.","Example":"","Deprecated":"false"},{"Env":"MIGRATE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"migrate deployment config data from charts table to deployment_config table","Example":"","Deprecated":"false"},{"Env":"PIPELINE_DEGRADED_TIME","EnvType":"string","EnvValue":"10","EnvDescription":"Time to mark a pipeline degraded if not healthy in defined time","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_DEVTRON_APP","EnvType":"int","EnvValue":"1","EnvDescription":"Count for devtron application rivision history","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_EXTERNAL_HELM_APP","EnvType":"int","EnvValue":"0","EnvDescription":"Count for external helm application rivision history","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_HELM_APP","EnvType":"int","EnvValue":"1","EnvDescription":"To set the history limit for the helm app being deployed through devtron","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_LINKED_HELM_APP","EnvType":"int","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS","EnvType":"bool","EnvValue":"false","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":"USE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"use deployment config data from deployment_config table","Example":"","Deprecated":"true"}]},{"Category":"CI_RUNNER","Fields":[{"Env":"AZURE_ACCOUNT_KEY","EnvType":"string","EnvValue":"","EnvDescription":"If blob storage is being used of azure then pass the secret key to access the bucket","Example":"","Deprecated":"false"},{"Env":"AZURE_ACCOUNT_NAME","EnvType":"string","EnvValue":"","EnvDescription":"Account name for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_CACHE","EnvType":"string","EnvValue":"","EnvDescription":"Cache bucket name for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_LOG","EnvType":"string","EnvValue":"","EnvDescription":"Log bucket for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_CONNECTION_INSECURE","EnvType":"bool","EnvValue":"true","EnvDescription":"Azure gateway connection allows insecure if true","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_URL","EnvType":"string","EnvValue":"http://devtron-minio.devtroncd:9000","EnvDescription":"Sent to CI runner for blob","Example":"","Deprecated":"false"},{"Env":"BASE_LOG_LOCATION_PATH","EnvType":"string","EnvValue":"/home/devtron/","EnvDescription":"Used to store, download logs of ci workflow, artifact","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_GCP_CREDENTIALS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"GCP cred json for GCS blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_PROVIDER","EnvType":"","EnvValue":"S3","EnvDescription":"Blob storage provider name(AWS/GCP/Azure)","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ACCESS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"S3 access key for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_BUCKET_VERSIONED","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable buctet versioning for blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT","EnvType":"string","EnvValue":"","EnvDescription":"S3 endpoint URL for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT_INSECURE","EnvType":"bool","EnvValue":"false","EnvDescription":"To use insecure s3 endpoint","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_SECRET_KEY","EnvType":"string","EnvValue":"","EnvDescription":"Secret key for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/devtron/buildx","EnvDescription":"Path for the buildx cache","Example":"","Deprecated":"false"},{"Env":"BUILDX_K8S_DRIVER_OPTIONS","EnvType":"string","EnvValue":"","EnvDescription":"To enable the k8s driver and pass args for k8s driver in buildx","Example":"","Deprecated":"false"},{"Env":"BUILDX_PROVENANCE_MODE","EnvType":"string","EnvValue":"","EnvDescription":"provinance is set to true by default by docker. this will add some build related data in generated build manifest.it also adds some unknown:unknown key:value pair which may not be compatible by some container registries. with buildx k8s driver , provinenance=true is causing issue when push manifest to quay registry, so setting it to false","Example":"","Deprecated":"false"},{"Env":"BUILD_LOG_TTL_VALUE_IN_SECS","EnvType":"int","EnvValue":"3600","EnvDescription":"This is the time that the pods of ci/pre-cd/post-cd live after completion state.","Example":"","Deprecated":"false"},{"Env":"CACHE_LIMIT","EnvType":"int64","EnvValue":"5000000000","EnvDescription":"Cache limit.","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"To pass the IP cidr for Pre/Post cd ","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"The subnet size to allocate from the base pool for CD","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"CPU Resource Limit Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"Memory Resource Limit Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"Node label selector for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"Toleration key for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"Toleration value for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"CPU Resource Rquest Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"Memory Resource Rquest Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"Executor type for Pre/Post CD(AWF,System)","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"cd-runner","EnvDescription":"Service account to be used in Pre/Post CD pod","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"To pass the IP cidr for CI","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"The subnet size to allocate from the base pool for CI","Example":"","Deprecated":"false"},{"Env":"CI_IGNORE_DOCKER_CACHE","EnvType":"bool","EnvValue":"","EnvDescription":"Ignoring docker cache ","Example":"","Deprecated":"false"},{"Env":"CI_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"Prefix for build logs","Example":"","Deprecated":"false"},{"Env":"CI_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"Node label selector for CI","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"Toleration key for CI","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"","EnvDescription":"Toleration value for CI","Example":"","Deprecated":"false"},{"Env":"CI_RUNNER_DOCKER_MTU_VALUE","EnvType":"int","EnvValue":"-1","EnvDescription":"this is to control the bytes of inofrmation passed in a network packet in ci-runner. default is -1 (defaults to the underlying node mtu value)","Example":"","Deprecated":"false"},{"Env":"CI_SUCCESS_AUTO_TRIGGER_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"this is to control the no of linked pipelines should be hanled in one go when a ci-success event of an parent ci is received","Example":"","Deprecated":"false"},{"Env":"CI_VOLUME_MOUNTS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"additional volume mount data for CI and JOB","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"Executor type for CI(AWF,System)","Example":"","Deprecated":"false"},{"Env":"DEFAULT_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"arsenal-v1/ci-artifacts","EnvDescription":"Key location for artifacts being created","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":"Bucket prefix for build logs","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET","EnvType":"string","EnvValue":"ci-caching","EnvDescription":"Bucket name for build cache","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"Build Cache bucket region","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"","EnvDescription":"Bucket prefix for build cache","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":"Namespace for devtron stack","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"Timeout for Pre/Post-Cd to be completed","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CI_IMAGE","EnvType":"string","EnvValue":"686244538589.dkr.ecr.us-east-2.amazonaws.com/cirunner:47","EnvDescription":"To pass the ci-runner image","Example":"","Deprecated":"false"},{"Env":"DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtron-ci","EnvDescription":"Timeout for CI to be completed","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TARGET_PLATFORM","EnvType":"string","EnvValue":"","EnvDescription":"Default architecture for buildx","Example":"","Deprecated":"false"},{"Env":"DOCKER_BUILD_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/docker","EnvDescription":"Path to store cache of docker build (/var/lib/docker-\u003e for legacy docker build, /var/lib/devtron-\u003e for buildx)","Example":"","Deprecated":"false"},{"Env":"ENABLE_BUILD_CONTEXT","EnvType":"bool","EnvValue":"false","EnvDescription":"To Enable build context in Devtron.","Example":"","Deprecated":"false"},{"Env":"ENABLE_WORKFLOW_EXECUTION_STAGE","EnvType":"bool","EnvValue":"true","EnvDescription":"if enabled then we will display build stages separately for CI/Job/Pre-Post CD","Example":"true","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_CM_NAME","EnvType":"string","EnvValue":"blob-storage-cm","EnvDescription":"name of the config map(contains bucket name, etc.) in external cluster when there is some operation related to external cluster, for example:-downloading cd artifact pushed in external cluster's env and we need to download from there, downloads ci logs pushed in external cluster's blob","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_SECRET_NAME","EnvType":"string","EnvValue":"blob-storage-secret","EnvDescription":"name of the secret(contains password, accessId,passKeys, etc.) in external cluster when there is some operation related to external cluster, for example:-downloading cd artifact pushed in external cluster's env and we need to download from there, downloads ci logs pushed in external cluster's blob","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"This is an array of strings used when submitting a workflow for pre or post-CD execution. If the ","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":"External CI API secret.","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":"External CI payload with project details.","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_WEB_HOOK_URL","EnvType":"string","EnvValue":"","EnvDescription":"default is {{HOST_URL}}/orchestrator/webhook/ext-ci. It is used for external ci.","Example":"","Deprecated":"false"},{"Env":"IGNORE_CM_CS_IN_CI_JOB","EnvType":"bool","EnvValue":"false","EnvDescription":"Ignore CM/CS in CI-pipeline as Job","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_COUNT","EnvType":"int","EnvValue":"0","EnvDescription":"push artifact(image) in ci retry count ","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_INTERVAL","EnvType":"int","EnvValue":"5","EnvDescription":"image retry interval takes value in seconds","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCANNER_ENDPOINT","EnvType":"string","EnvValue":"http://image-scanner-new-demo-devtroncd-service.devtroncd:80","EnvDescription":"Image-scanner micro-service URL","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_MAX_RETRIES","EnvType":"int","EnvValue":"3","EnvDescription":"Max retry count for image-scanning","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"Delay for the image-scaning to start","Example":"","Deprecated":"false"},{"Env":"IN_APP_LOGGING_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"Used in case of argo workflow is enabled. If enabled logs push will be managed by us, else will be managed by argo workflow.","Example":"","Deprecated":"false"},{"Env":"MAX_CD_WORKFLOW_RUNNER_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"Maximum time pre/post-cd-workflow create pod if it fails to complete","Example":"","Deprecated":"false"},{"Env":"MAX_CI_WORKFLOW_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"Maximum time CI-workflow create pod if it fails to complete","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":"Orchestrator micro-service URL ","Example":"","Deprecated":"false"},{"Env":"ORCH_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"Orchestrator token","Example":"","Deprecated":"false"},{"Env":"PRE_CI_CACHE_PATH","EnvType":"string","EnvValue":"/devtroncd-cache","EnvDescription":"Cache path for Pre CI tasks","Example":"","Deprecated":"false"},{"Env":"SHOW_DOCKER_BUILD_ARGS","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable showing the args passed for CI in build logs","Example":"","Deprecated":"false"},{"Env":"SKIP_CI_JOB_BUILD_CACHE_PUSH_PULL","EnvType":"bool","EnvValue":"false","EnvDescription":"To skip cache Push/Pull for ci job","Example":"","Deprecated":"false"},{"Env":"SKIP_CREATING_ECR_REPO","EnvType":"bool","EnvValue":"false","EnvDescription":"By disabling this ECR repo won't get created if it's not available on ECR from build configuration","Example":"","Deprecated":"false"},{"Env":"TERMINATION_GRACE_PERIOD_SECS","EnvType":"int","EnvValue":"180","EnvDescription":"this is the time given to workflow pods to shutdown. (grace full termination time)","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_QUERY_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 query for listing artifacts","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable blob storage in pre and post cd","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CI_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable blob storage in pre and post ci","Example":"","Deprecated":"false"},{"Env":"USE_BUILDX","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable buildx feature globally","Example":"","Deprecated":"false"},{"Env":"USE_DOCKER_API_TO_GET_DIGEST","EnvType":"bool","EnvValue":"false","EnvDescription":"when user do not pass the digest then this flag controls , finding the image digest using docker API or not. if set to true we get the digest from docker API call else use docker pull command. [logic in ci-runner]","Example":"","Deprecated":"false"},{"Env":"USE_EXTERNAL_NODE","EnvType":"bool","EnvValue":"false","EnvDescription":"It is used in case of Pre/ Post Cd with run in application mode. If enabled the node lebels are read from EXTERNAL_CD_NODE_LABEL_SELECTOR else from CD_NODE_LABEL_SELECTOR MODE: if the vale is DEV, it will read the local kube config file or else from the cluser location.","Example":"","Deprecated":"false"},{"Env":"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD","EnvType":"bool","EnvValue":"false","EnvDescription":"To use the same tag in container image as that of git tag","Example":"","Deprecated":"false"},{"Env":"WF_CONTROLLER_INSTANCE_ID","EnvType":"string","EnvValue":"devtron-runner","EnvDescription":"Workflow controller instance ID.","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_CACHE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"flag is used to configure how Docker caches are handled during a CI/CD ","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":"ADDITIONAL_NODE_GROUP_LABELS","EnvType":"","EnvValue":"","EnvDescription":"Add comma separated list of additional node group labels to default labels","Example":"karpenter.sh/nodepool,cloud.google.com/gke-nodepool","Deprecated":"false"},{"Env":"APP_SYNC_IMAGE","EnvType":"string","EnvValue":"quay.io/devtron/chart-sync:1227622d-132-3775","EnvDescription":"For the app sync image, this image will be used in app-manual sync job","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_JOB_RESOURCES_OBJ","EnvType":"string","EnvValue":"","EnvDescription":"To pass the resource of app sync","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"Service account to be used in app sync Job","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SHUTDOWN_WAIT_DURATION","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_AUTO_SYNC_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"If enabled all argocd application will have auto sync enabled","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT","EnvType":"int","EnvValue":"3","EnvDescription":"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT","EnvType":"int","EnvValue":"1","EnvDescription":"Delay on retrying the maifest commit the on gitops","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_COUNT","EnvType":"int","EnvValue":"3","EnvDescription":"Argo app registration in argo retries on deployment","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_DELAY","EnvType":"int","EnvValue":"10","EnvDescription":"Argo app registration in argo cd on deployment delay between retry","Example":"","Deprecated":"false"},{"Env":"ASYNC_BUILDX_CACHE_EXPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async container image cache export","Example":"","Deprecated":"false"},{"Env":"BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"there is feature to get URL's of services/ingresses. so to extract those, we need to parse all the servcie and ingress objects of the application. this BATCH_SIZE flag controls the no of these objects get parsed in one go.","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":"To set build cache mode to minimum in buildx","Example":"","Deprecated":"false"},{"Env":"CD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Host for the devtron stack","Example":"","Deprecated":"false"},{"Env":"CD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PORT","EnvType":"string","EnvValue":"8000","EnvDescription":"Port for pre/post-cd","Example":"","Deprecated":"false"},{"Env":"CExpirationTime","EnvType":"int","EnvValue":"600","EnvDescription":"Caching expiration time.","Example":"","Deprecated":"false"},{"Env":"CI_TRIGGER_CRON_TIME","EnvType":"int","EnvValue":"2","EnvDescription":"For image poll plugin","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_STATUS_UPDATE_CRON","EnvType":"string","EnvValue":"*/5 * * * *","EnvDescription":"Cron schedule for CI pipeline status","Example":"","Deprecated":"false"},{"Env":"CLI_CMD_TIMEOUT_GLOBAL_SECONDS","EnvType":"int","EnvValue":"0","EnvDescription":"Used in git cli opeartion timeout","Example":"","Deprecated":"false"},{"Env":"CLUSTER_STATUS_CRON_TIME","EnvType":"int","EnvValue":"15","EnvDescription":"Cron schedule for cluster status on resource browser","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":"Timeout for CI to be completed","Example":"","Deprecated":"false"},{"Env":"DEVTRON_BOM_URL","EnvType":"string","EnvValue":"https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml","EnvDescription":"Path to devtron-bom.yaml of devtron charts, used for module installation and devtron upgrade","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":"Namespace of dex secret","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":"Name of the Devtron Helm release. ","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace of the Devtron Helm release","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"Is used to install modules (stack manager)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_URL","EnvType":"string","EnvValue":"https://helm.devtron.ai","EnvDescription":"Is used to install modules (stack manager)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLATION_TYPE","EnvType":"string","EnvValue":"","EnvDescription":"Devtron Installation type(EA/Full)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLER_MODULES_PATH","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"Path to devtron installer modules, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLER_RELEASE_PATH","EnvType":"string","EnvValue":"installer.release","EnvDescription":"Path to devtron installer release, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_MODULES_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_OPERATOR_BASE_PATH","EnvType":"string","EnvValue":"","EnvDescription":"Base path for devtron operator, used to find the helm charts and values files","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":"devtron operator version identifier in helm values yaml","Example":"","Deprecated":"false"},{"Env":"DEX_CID","EnvType":"string","EnvValue":"example-app","EnvDescription":"dex client id ","Example":"","Deprecated":"false"},{"Env":"DEX_CLIENT_ID","EnvType":"string","EnvValue":"argo-cd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CSTOREKEY","EnvType":"string","EnvValue":"","EnvDescription":"DEX CSTOREKEY.","Example":"","Deprecated":"false"},{"Env":"DEX_JWTKEY","EnvType":"string","EnvValue":"","EnvDescription":"DEX JWT key. ","Example":"","Deprecated":"false"},{"Env":"DEX_RURL","EnvType":"string","EnvValue":"http://127.0.0.1:8080/callback","EnvDescription":"Dex redirect URL(http://argocd-dex-server.devtroncd:8080/callback)","Example":"","Deprecated":"false"},{"Env":"DEX_SCOPES","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_SECRET","EnvType":"string","EnvValue":"","EnvDescription":"Dex secret","Example":"","Deprecated":"false"},{"Env":"DEX_URL","EnvType":"string","EnvValue":"","EnvDescription":"Dex service endpoint with dex path(http://argocd-dex-server.devtroncd:5556/dex)","Example":"","Deprecated":"false"},{"Env":"ECR_REPO_NAME_PREFIX","EnvType":"string","EnvValue":"test/","EnvDescription":"Prefix for ECR repo to be created in does not exist","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async installation of gitops application","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async installation of no-gitops application","Example":"","Deprecated":"false"},{"Env":"ENABLE_NOTIFIER_V2","EnvType":"bool","EnvValue":"false","EnvDescription":"enable notifier v2","Example":"","Deprecated":"false"},{"Env":"EPHEMERAL_SERVER_VERSION_REGEX","EnvType":"string","EnvValue":"v[1-9]\\.\\b(2[3-9]\\|[3-9][0-9])\\b.*","EnvDescription":"ephemeral containers support version regex that is compared with k8sServerVersion","Example":"","Deprecated":"false"},{"Env":"EVENT_URL","EnvType":"string","EnvValue":"http://localhost:3000/notify","EnvDescription":"Notifier service url","Example":"","Deprecated":"false"},{"Env":"EXECUTE_WIRE_NIL_CHECKER","EnvType":"bool","EnvValue":"false","EnvDescription":"checks for any nil pointer in wire.go","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CI_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"To expose CI metrics","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"restart workload retrieval batch size ","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"restart workload retrieval pool size","Example":"","Deprecated":"false"},{"Env":"FORCE_SECURITY_SCANNING","EnvType":"bool","EnvValue":"false","EnvDescription":"By enabling this no one can disable image scaning on ci-pipeline from UI","Example":"","Deprecated":"false"},{"Env":"GITOPS_REPO_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"Prefix for Gitops repo being creation for argocd application","Example":"","Deprecated":"false"},{"Env":"GO_RUNTIME_ENV","EnvType":"string","EnvValue":"production","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Host URL for the grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace for grafana","Example":"","Deprecated":"false"},{"Env":"GRAFANA_ORG_ID","EnvType":"int","EnvValue":"2","EnvDescription":"Org ID for grafana for application metrics","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PASSWORD","EnvType":"string","EnvValue":"prom-operator","EnvDescription":"Password for grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PORT","EnvType":"string","EnvValue":"8090","EnvDescription":"Port for grafana micro-service","Example":"","Deprecated":"false"},{"Env":"GRAFANA_URL","EnvType":"string","EnvValue":"","EnvDescription":"Host URL for the grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"Username for grafana ","Example":"","Deprecated":"false"},{"Env":"HIDE_IMAGE_TAGGING_HARD_DELETE","EnvType":"bool","EnvValue":"false","EnvDescription":"Flag to hide the hard delete option in the image tagging service","Example":"","Deprecated":"false"},{"Env":"IGNORE_AUTOCOMPLETE_AUTH_CHECK","EnvType":"bool","EnvValue":"false","EnvDescription":"flag for ignoring auth check in autocomplete apis.","Example":"","Deprecated":"false"},{"Env":"INSTALLED_MODULES","EnvType":"","EnvValue":"","EnvDescription":"List of installed modules given in helm values/yaml are written in cm and used by devtron to know which modules are given","Example":"security.trivy,security.clair","Deprecated":"false"},{"Env":"INSTALLER_CRD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"namespace where Custom Resource Definitions get installed","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_GROUP_NAME","EnvType":"string","EnvValue":"installer.devtron.ai","EnvDescription":"Devtron installer CRD group name, partially deprecated.","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_RESOURCE","EnvType":"string","EnvValue":"installers","EnvDescription":"Devtron installer CRD resource name, partially deprecated","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_VERSION","EnvType":"string","EnvValue":"v1alpha1","EnvDescription":"version of the CRDs. default is v1alpha1","Example":"","Deprecated":"false"},{"Env":"IS_AIR_GAP_ENVIRONMENT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"JwtExpirationTime","EnvType":"int","EnvValue":"120","EnvDescription":"JWT expiration time.","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":"LENS_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"Lens microservice timeout.","Example":"","Deprecated":"false"},{"Env":"LENS_URL","EnvType":"string","EnvValue":"http://lens-milandevtron-service:80","EnvDescription":"Lens micro-service URL","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":"Enables a different logger theme.","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_SESSION_PER_USER","EnvType":"int","EnvValue":"5","EnvDescription":"max no of cluster terminal pods can be created by an user","Example":"","Deprecated":"false"},{"Env":"MODULE_METADATA_API_URL","EnvType":"string","EnvValue":"https://api.devtron.ai/module?name=%s","EnvDescription":"Modules list and meta info will be fetched from this server, that is central api server of devtron.","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":"notification medium","Example":"","Deprecated":"false"},{"Env":"OTEL_COLLECTOR_URL","EnvType":"string","EnvValue":"","EnvDescription":"Opentelemetry URL ","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"","EnvDescription":"App manual sync job parallel tag processing count.","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":"Handles image retrieval from a container repository and triggers subsequent CI processes upon detecting new images.Current default plugin name: Pull Images from Container Repository.","Example":"","Deprecated":"false"},{"Env":"PROPAGATE_EXTRA_LABELS","EnvType":"bool","EnvValue":"false","EnvDescription":"Add additional propagate labels like api.devtron.ai/appName, api.devtron.ai/envName, api.devtron.ai/project along with the user defined ones.","Example":"","Deprecated":"false"},{"Env":"PROXY_SERVICE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"Proxy configuration for micro-service to be accessible on orhcestrator ingress","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":"To restrict the cluster terminal from user having non-super admin acceess","Example":"","Deprecated":"false"},{"Env":"RUNTIME_CONFIG_LOCAL_DEV","EnvType":"LocalDevMode","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable scoped variable option","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_FORMAT","EnvType":"string","EnvValue":"@{{%s}}","EnvDescription":"Its a scope format for varialbe name.","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_HANDLE_PRIMITIVES","EnvType":"bool","EnvValue":"false","EnvDescription":"This describe should we handle primitives or not in scoped variable template parsing.","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":"Regex for scoped variable name that must passed this regex.","Example":"","Deprecated":"false"},{"Env":"SOCKET_DISCONNECT_DELAY_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"The server closes a session when a client receiving connection have not been seen for a while.This delay is configured by this setting. By default the session is closed when a receiving connection wasn't seen for 5 seconds.","Example":"","Deprecated":"false"},{"Env":"SOCKET_HEARTBEAT_SECONDS","EnvType":"int","EnvValue":"25","EnvDescription":"In order to keep proxies and load balancers from closing long running http requests we need to pretend that the connection is active and send a heartbeat packet once in a while. This setting controls how often this is done. By default a heartbeat packet is sent every 25 seconds.","Example":"","Deprecated":"false"},{"Env":"STREAM_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SYSTEM_VAR_PREFIX","EnvType":"string","EnvValue":"DEVTRON_","EnvDescription":"Scoped variable prefix, variable name must have this prefix.","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"default","EnvDescription":"Cluster terminal default namespace","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_INACTIVE_DURATION_IN_MINS","EnvType":"int","EnvValue":"10","EnvDescription":"Timeout for cluster terminal to be inactive","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_STATUS_SYNC_In_SECS","EnvType":"int","EnvValue":"600","EnvDescription":"this is the time interval at which the status of the cluster terminal pod","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":"Timeout for Failed CI build ","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_IN_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"timeout to compute the urls from services and ingress objects of an application","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":"To use the V2 API for listing artifacts in Listing the images in pipeline","Example":"","Deprecated":"false"},{"Env":"USE_CUSTOM_HTTP_TRANSPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_GIT_CLI","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable git cli","Example":"","Deprecated":"false"},{"Env":"USE_RBAC_CREATION_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 for RBAC creation","Example":"","Deprecated":"false"},{"Env":"VARIABLE_CACHE_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"This is used to control caching of all the scope variables defined in the system.","Example":"","Deprecated":"false"},{"Env":"VARIABLE_EXPRESSION_REGEX","EnvType":"string","EnvValue":"@{{([^}]+)}}","EnvDescription":"Scoped variable expression regex","Example":"","Deprecated":"false"},{"Env":"WEBHOOK_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"If you want to continue using jenkins for CI then please provide this for authentication of requests","Example":"","Deprecated":"false"}]},{"Category":"GITOPS","Fields":[{"Env":"ACD_CM","EnvType":"string","EnvValue":"argocd-cm","EnvDescription":"Name of the argocd CM","Example":"","Deprecated":"false"},{"Env":"ACD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"To pass the argocd namespace","Example":"","Deprecated":"false"},{"Env":"ACD_PASSWORD","EnvType":"string","EnvValue":"","EnvDescription":"Password for the Argocd (deprecated)","Example":"","Deprecated":"false"},{"Env":"ACD_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"User name for argocd","Example":"","Deprecated":"false"},{"Env":"GITOPS_SECRET_NAME","EnvType":"string","EnvValue":"devtron-gitops-secret","EnvDescription":"devtron-gitops-secret","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS","EnvType":"string","EnvValue":"Deployment,Rollout,StatefulSet,ReplicaSet","EnvDescription":"this holds the list of k8s resource names which support replicas key. this list used in hibernate/un hibernate process","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS_BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"this the batch size to control no of above resources can be parsed in one go to determine hibernate status","Example":"","Deprecated":"false"}]},{"Category":"INFRA_SETUP","Fields":[{"Env":"DASHBOARD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Dashboard micro-service URL","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Dashboard micro-service namespace","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_PORT","EnvType":"string","EnvValue":"3000","EnvDescription":"Port for dashboard micro-service","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":"Protocol to connect with git-sensor micro-service","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_SERVICE_CONFIG","EnvType":"string","EnvValue":"{\"loadBalancingPolicy\":\"pick_first\"}","EnvDescription":"git-sensor grpc service config","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"Timeout for getting response from the git-sensor","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_URL","EnvType":"string","EnvValue":"127.0.0.1:7070","EnvDescription":"git-sensor micro-service url ","Example":"","Deprecated":"false"},{"Env":"HELM_CLIENT_URL","EnvType":"string","EnvValue":"127.0.0.1:50051","EnvDescription":"Kubelink micro-service url ","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":"KUBELINK_GRPC_SERVICE_CONFIG","EnvType":"string","EnvValue":"{\"loadBalancingPolicy\":\"round_robin\"}","EnvDescription":"kubelink grpc service config","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":"Database for casbin","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":"Time out for read operation in postgres","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":"Time out for write operation in postgres","Example":"","Deprecated":"false"}]},{"Category":"RBAC","Fields":[{"Env":"ENFORCER_CACHE","EnvType":"bool","EnvValue":"false","EnvDescription":"To Enable enforcer cache.","Example":"","Deprecated":"false"},{"Env":"ENFORCER_CACHE_EXPIRATION_IN_SEC","EnvType":"int","EnvValue":"86400","EnvDescription":"Expiration time (in seconds) for enforcer cache. ","Example":"","Deprecated":"false"},{"Env":"ENFORCER_MAX_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"Maximum batch size for the enforcer.","Example":"","Deprecated":"false"},{"Env":"USE_CASBIN_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable casbin V2 API","Example":"","Deprecated":"false"}]}] \ No newline at end of file +[{"Category":"CD","Fields":[{"Env":"ARGO_APP_MANUAL_SYNC_TIME","EnvType":"int","EnvValue":"3","EnvDescription":"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)","Example":"","Deprecated":"false"},{"Env":"CD_HELM_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time to check the pipeline status ","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"Cron time for CD pipeline status","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_TIMEOUT_DURATION","EnvType":"string","EnvValue":"20","EnvDescription":"Timeout for CD pipeline to get healthy","Example":"","Deprecated":"false"},{"Env":"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS","EnvType":"int","EnvValue":"12","EnvDescription":"This flag is used to fetch the deployment status of the application. It retrieves the status of deployments that occurred between 12 hours and 10 minutes prior to the current time. It fetches non-terminal statuses.","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"1","EnvDescription":"Context timeout for gitops concurrent async deployments","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"6","EnvDescription":"Context timeout for no gitops concurrent async deployments","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CD_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_MIGRATE_ARGOCD_APPLICATION_ENABLE","EnvType":"bool","EnvValue":"false","EnvDescription":"enable migration of external argocd application to devtron pipeline","Example":"","Deprecated":"false"},{"Env":"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"eligible time for checking helm app status periodically and update in db, value is in seconds., default is 120, if wfr is updated within configured time i.e. HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME then do not include for this cron cycle.","Example":"","Deprecated":"false"},{"Env":"IS_INTERNAL_USE","EnvType":"bool","EnvValue":"true","EnvDescription":"If enabled then cd pipeline and helm apps will not need the deployment app type mandatorily. Couple this flag with HIDE_GITOPS_OR_HELM_OPTION (in Dashborad) and if gitops is configured and allowed for the env, pipeline/ helm app will gitops else no-gitops.","Example":"","Deprecated":"false"},{"Env":"MIGRATE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"migrate deployment config data from charts table to deployment_config table","Example":"","Deprecated":"false"},{"Env":"PIPELINE_DEGRADED_TIME","EnvType":"string","EnvValue":"10","EnvDescription":"Time to mark a pipeline degraded if not healthy in defined time","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_DEVTRON_APP","EnvType":"int","EnvValue":"1","EnvDescription":"Count for devtron application rivision history","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_EXTERNAL_HELM_APP","EnvType":"int","EnvValue":"0","EnvDescription":"Count for external helm application rivision history","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_HELM_APP","EnvType":"int","EnvValue":"1","EnvDescription":"To set the history limit for the helm app being deployed through devtron","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_LINKED_HELM_APP","EnvType":"int","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS","EnvType":"bool","EnvValue":"false","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":"USE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"use deployment config data from deployment_config table","Example":"","Deprecated":"true"}]},{"Category":"CI_RUNNER","Fields":[{"Env":"AZURE_ACCOUNT_KEY","EnvType":"string","EnvValue":"","EnvDescription":"If blob storage is being used of azure then pass the secret key to access the bucket","Example":"","Deprecated":"false"},{"Env":"AZURE_ACCOUNT_NAME","EnvType":"string","EnvValue":"","EnvDescription":"Account name for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_CACHE","EnvType":"string","EnvValue":"","EnvDescription":"Cache bucket name for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_LOG","EnvType":"string","EnvValue":"","EnvDescription":"Log bucket for azure blob storage","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_CONNECTION_INSECURE","EnvType":"bool","EnvValue":"true","EnvDescription":"Azure gateway connection allows insecure if true","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_URL","EnvType":"string","EnvValue":"http://devtron-minio.devtroncd:9000","EnvDescription":"Sent to CI runner for blob","Example":"","Deprecated":"false"},{"Env":"BASE_LOG_LOCATION_PATH","EnvType":"string","EnvValue":"/home/devtron/","EnvDescription":"Used to store, download logs of ci workflow, artifact","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_GCP_CREDENTIALS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"GCP cred json for GCS blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_PROVIDER","EnvType":"","EnvValue":"S3","EnvDescription":"Blob storage provider name(AWS/GCP/Azure)","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ACCESS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"S3 access key for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_BUCKET_VERSIONED","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable buctet versioning for blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT","EnvType":"string","EnvValue":"","EnvDescription":"S3 endpoint URL for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT_INSECURE","EnvType":"bool","EnvValue":"false","EnvDescription":"To use insecure s3 endpoint","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_SECRET_KEY","EnvType":"string","EnvValue":"","EnvDescription":"Secret key for s3 blob storage","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/devtron/buildx","EnvDescription":"Path for the buildx cache","Example":"","Deprecated":"false"},{"Env":"BUILDX_K8S_DRIVER_OPTIONS","EnvType":"string","EnvValue":"","EnvDescription":"To enable the k8s driver and pass args for k8s driver in buildx","Example":"","Deprecated":"false"},{"Env":"BUILDX_PROVENANCE_MODE","EnvType":"string","EnvValue":"","EnvDescription":"provinance is set to true by default by docker. this will add some build related data in generated build manifest.it also adds some unknown:unknown key:value pair which may not be compatible by some container registries. with buildx k8s driver , provinenance=true is causing issue when push manifest to quay registry, so setting it to false","Example":"","Deprecated":"false"},{"Env":"BUILD_LOG_TTL_VALUE_IN_SECS","EnvType":"int","EnvValue":"3600","EnvDescription":"This is the time that the pods of ci/pre-cd/post-cd live after completion state.","Example":"","Deprecated":"false"},{"Env":"CACHE_LIMIT","EnvType":"int64","EnvValue":"5000000000","EnvDescription":"Cache limit.","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"To pass the IP cidr for Pre/Post cd ","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"The subnet size to allocate from the base pool for CD","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"CPU Resource Limit Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"Memory Resource Limit Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"Node label selector for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"Toleration key for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"Toleration value for Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"CPU Resource Rquest Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"Memory Resource Rquest Pre/Post CD","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"Executor type for Pre/Post CD(AWF,System)","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"cd-runner","EnvDescription":"Service account to be used in Pre/Post CD pod","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"To pass the IP cidr for CI","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"The subnet size to allocate from the base pool for CI","Example":"","Deprecated":"false"},{"Env":"CI_IGNORE_DOCKER_CACHE","EnvType":"bool","EnvValue":"","EnvDescription":"Ignoring docker cache ","Example":"","Deprecated":"false"},{"Env":"CI_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"Prefix for build logs","Example":"","Deprecated":"false"},{"Env":"CI_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"Node label selector for CI","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"Toleration key for CI","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"","EnvDescription":"Toleration value for CI","Example":"","Deprecated":"false"},{"Env":"CI_RUNNER_DOCKER_MTU_VALUE","EnvType":"int","EnvValue":"-1","EnvDescription":"this is to control the bytes of inofrmation passed in a network packet in ci-runner. default is -1 (defaults to the underlying node mtu value)","Example":"","Deprecated":"false"},{"Env":"CI_SUCCESS_AUTO_TRIGGER_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"this is to control the no of linked pipelines should be hanled in one go when a ci-success event of an parent ci is received","Example":"","Deprecated":"false"},{"Env":"CI_VOLUME_MOUNTS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"additional volume mount data for CI and JOB","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"Executor type for CI(AWF,System)","Example":"","Deprecated":"false"},{"Env":"DEFAULT_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"arsenal-v1/ci-artifacts","EnvDescription":"Key location for artifacts being created","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":"Bucket prefix for build logs","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET","EnvType":"string","EnvValue":"ci-caching","EnvDescription":"Bucket name for build cache","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"Build Cache bucket region","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"","EnvDescription":"Bucket prefix for build cache","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":"Namespace for devtron stack","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"Timeout for Pre/Post-Cd to be completed","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CI_IMAGE","EnvType":"string","EnvValue":"686244538589.dkr.ecr.us-east-2.amazonaws.com/cirunner:47","EnvDescription":"To pass the ci-runner image","Example":"","Deprecated":"false"},{"Env":"DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtron-ci","EnvDescription":"Timeout for CI to be completed","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TARGET_PLATFORM","EnvType":"string","EnvValue":"","EnvDescription":"Default architecture for buildx","Example":"","Deprecated":"false"},{"Env":"DOCKER_BUILD_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/docker","EnvDescription":"Path to store cache of docker build (/var/lib/docker-\u003e for legacy docker build, /var/lib/devtron-\u003e for buildx)","Example":"","Deprecated":"false"},{"Env":"ENABLE_BUILD_CONTEXT","EnvType":"bool","EnvValue":"false","EnvDescription":"To Enable build context in Devtron.","Example":"","Deprecated":"false"},{"Env":"ENABLE_WORKFLOW_EXECUTION_STAGE","EnvType":"bool","EnvValue":"true","EnvDescription":"if enabled then we will display build stages separately for CI/Job/Pre-Post CD","Example":"true","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_CM_NAME","EnvType":"string","EnvValue":"blob-storage-cm","EnvDescription":"name of the config map(contains bucket name, etc.) in external cluster when there is some operation related to external cluster, for example:-downloading cd artifact pushed in external cluster's env and we need to download from there, downloads ci logs pushed in external cluster's blob","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_SECRET_NAME","EnvType":"string","EnvValue":"blob-storage-secret","EnvDescription":"name of the secret(contains password, accessId,passKeys, etc.) in external cluster when there is some operation related to external cluster, for example:-downloading cd artifact pushed in external cluster's env and we need to download from there, downloads ci logs pushed in external cluster's blob","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"This is an array of strings used when submitting a workflow for pre or post-CD execution. If the ","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":"External CI API secret.","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":"External CI payload with project details.","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_WEB_HOOK_URL","EnvType":"string","EnvValue":"","EnvDescription":"default is {{HOST_URL}}/orchestrator/webhook/ext-ci. It is used for external ci.","Example":"","Deprecated":"false"},{"Env":"IGNORE_CM_CS_IN_CI_JOB","EnvType":"bool","EnvValue":"false","EnvDescription":"Ignore CM/CS in CI-pipeline as Job","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_COUNT","EnvType":"int","EnvValue":"0","EnvDescription":"push artifact(image) in ci retry count ","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_INTERVAL","EnvType":"int","EnvValue":"5","EnvDescription":"image retry interval takes value in seconds","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCANNER_ENDPOINT","EnvType":"string","EnvValue":"http://image-scanner-new-demo-devtroncd-service.devtroncd:80","EnvDescription":"Image-scanner micro-service URL","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_MAX_RETRIES","EnvType":"int","EnvValue":"3","EnvDescription":"Max retry count for image-scanning","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"Delay for the image-scaning to start","Example":"","Deprecated":"false"},{"Env":"IN_APP_LOGGING_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"Used in case of argo workflow is enabled. If enabled logs push will be managed by us, else will be managed by argo workflow.","Example":"","Deprecated":"false"},{"Env":"MAX_CD_WORKFLOW_RUNNER_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"Maximum time pre/post-cd-workflow create pod if it fails to complete","Example":"","Deprecated":"false"},{"Env":"MAX_CI_WORKFLOW_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"Maximum time CI-workflow create pod if it fails to complete","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":"Orchestrator micro-service URL ","Example":"","Deprecated":"false"},{"Env":"ORCH_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"Orchestrator token","Example":"","Deprecated":"false"},{"Env":"PRE_CI_CACHE_PATH","EnvType":"string","EnvValue":"/devtroncd-cache","EnvDescription":"Cache path for Pre CI tasks","Example":"","Deprecated":"false"},{"Env":"SHOW_DOCKER_BUILD_ARGS","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable showing the args passed for CI in build logs","Example":"","Deprecated":"false"},{"Env":"SKIP_CI_JOB_BUILD_CACHE_PUSH_PULL","EnvType":"bool","EnvValue":"false","EnvDescription":"To skip cache Push/Pull for ci job","Example":"","Deprecated":"false"},{"Env":"SKIP_CREATING_ECR_REPO","EnvType":"bool","EnvValue":"false","EnvDescription":"By disabling this ECR repo won't get created if it's not available on ECR from build configuration","Example":"","Deprecated":"false"},{"Env":"TERMINATION_GRACE_PERIOD_SECS","EnvType":"int","EnvValue":"180","EnvDescription":"this is the time given to workflow pods to shutdown. (grace full termination time)","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_QUERY_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 query for listing artifacts","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable blob storage in pre and post cd","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CI_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable blob storage in pre and post ci","Example":"","Deprecated":"false"},{"Env":"USE_BUILDX","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable buildx feature globally","Example":"","Deprecated":"false"},{"Env":"USE_DOCKER_API_TO_GET_DIGEST","EnvType":"bool","EnvValue":"false","EnvDescription":"when user do not pass the digest then this flag controls , finding the image digest using docker API or not. if set to true we get the digest from docker API call else use docker pull command. [logic in ci-runner]","Example":"","Deprecated":"false"},{"Env":"USE_EXTERNAL_NODE","EnvType":"bool","EnvValue":"false","EnvDescription":"It is used in case of Pre/ Post Cd with run in application mode. If enabled the node lebels are read from EXTERNAL_CD_NODE_LABEL_SELECTOR else from CD_NODE_LABEL_SELECTOR MODE: if the vale is DEV, it will read the local kube config file or else from the cluser location.","Example":"","Deprecated":"false"},{"Env":"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD","EnvType":"bool","EnvValue":"false","EnvDescription":"To use the same tag in container image as that of git tag","Example":"","Deprecated":"false"},{"Env":"WF_CONTROLLER_INSTANCE_ID","EnvType":"string","EnvValue":"devtron-runner","EnvDescription":"Workflow controller instance ID.","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_CACHE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"flag is used to configure how Docker caches are handled during a CI/CD ","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":"ADDITIONAL_NODE_GROUP_LABELS","EnvType":"","EnvValue":"","EnvDescription":"Add comma separated list of additional node group labels to default labels","Example":"karpenter.sh/nodepool,cloud.google.com/gke-nodepool","Deprecated":"false"},{"Env":"APP_SYNC_IMAGE","EnvType":"string","EnvValue":"quay.io/devtron/chart-sync:1227622d-132-3775","EnvDescription":"For the app sync image, this image will be used in app-manual sync job","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_JOB_RESOURCES_OBJ","EnvType":"string","EnvValue":"","EnvDescription":"To pass the resource of app sync","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"Service account to be used in app sync Job","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SHUTDOWN_WAIT_DURATION","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_AUTO_SYNC_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"If enabled all argocd application will have auto sync enabled","Example":"true","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT","EnvType":"int","EnvValue":"3","EnvDescription":"retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins)","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT","EnvType":"int","EnvValue":"1","EnvDescription":"Delay on retrying the maifest commit the on gitops","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_COUNT","EnvType":"int","EnvValue":"4","EnvDescription":"Retry count for registering a GitOps repository to ArgoCD","Example":"3","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"Delay (in Seconds) between the retries for registering a GitOps repository to ArgoCD","Example":"5","Deprecated":"false"},{"Env":"ASYNC_BUILDX_CACHE_EXPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async container image cache export","Example":"","Deprecated":"false"},{"Env":"BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"there is feature to get URL's of services/ingresses. so to extract those, we need to parse all the servcie and ingress objects of the application. this BATCH_SIZE flag controls the no of these objects get parsed in one go.","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":"To set build cache mode to minimum in buildx","Example":"","Deprecated":"false"},{"Env":"CD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Host for the devtron stack","Example":"","Deprecated":"false"},{"Env":"CD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PORT","EnvType":"string","EnvValue":"8000","EnvDescription":"Port for pre/post-cd","Example":"","Deprecated":"false"},{"Env":"CExpirationTime","EnvType":"int","EnvValue":"600","EnvDescription":"Caching expiration time.","Example":"","Deprecated":"false"},{"Env":"CI_TRIGGER_CRON_TIME","EnvType":"int","EnvValue":"2","EnvDescription":"For image poll plugin","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_STATUS_UPDATE_CRON","EnvType":"string","EnvValue":"*/5 * * * *","EnvDescription":"Cron schedule for CI pipeline status","Example":"","Deprecated":"false"},{"Env":"CLI_CMD_TIMEOUT_GLOBAL_SECONDS","EnvType":"int","EnvValue":"0","EnvDescription":"Used in git cli opeartion timeout","Example":"","Deprecated":"false"},{"Env":"CLUSTER_STATUS_CRON_TIME","EnvType":"int","EnvValue":"15","EnvDescription":"Cron schedule for cluster status on resource browser","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":"Timeout for CI to be completed","Example":"","Deprecated":"false"},{"Env":"DEVTRON_BOM_URL","EnvType":"string","EnvValue":"https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml","EnvDescription":"Path to devtron-bom.yaml of devtron charts, used for module installation and devtron upgrade","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":"Namespace of dex secret","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":"Name of the Devtron Helm release. ","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace of the Devtron Helm release","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"Is used to install modules (stack manager)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_URL","EnvType":"string","EnvValue":"https://helm.devtron.ai","EnvDescription":"Is used to install modules (stack manager)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLATION_TYPE","EnvType":"string","EnvValue":"","EnvDescription":"Devtron Installation type(EA/Full)","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLER_MODULES_PATH","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"Path to devtron installer modules, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLER_RELEASE_PATH","EnvType":"string","EnvValue":"installer.release","EnvDescription":"Path to devtron installer release, used to find the helm charts and values files","Example":"","Deprecated":"false"},{"Env":"DEVTRON_MODULES_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_OPERATOR_BASE_PATH","EnvType":"string","EnvValue":"","EnvDescription":"Base path for devtron operator, used to find the helm charts and values files","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":"devtron operator version identifier in helm values yaml","Example":"","Deprecated":"false"},{"Env":"DEX_CID","EnvType":"string","EnvValue":"example-app","EnvDescription":"dex client id ","Example":"","Deprecated":"false"},{"Env":"DEX_CLIENT_ID","EnvType":"string","EnvValue":"argo-cd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CSTOREKEY","EnvType":"string","EnvValue":"","EnvDescription":"DEX CSTOREKEY.","Example":"","Deprecated":"false"},{"Env":"DEX_JWTKEY","EnvType":"string","EnvValue":"","EnvDescription":"DEX JWT key. ","Example":"","Deprecated":"false"},{"Env":"DEX_RURL","EnvType":"string","EnvValue":"http://127.0.0.1:8080/callback","EnvDescription":"Dex redirect URL(http://argocd-dex-server.devtroncd:8080/callback)","Example":"","Deprecated":"false"},{"Env":"DEX_SCOPES","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_SECRET","EnvType":"string","EnvValue":"","EnvDescription":"Dex secret","Example":"","Deprecated":"false"},{"Env":"DEX_URL","EnvType":"string","EnvValue":"","EnvDescription":"Dex service endpoint with dex path(http://argocd-dex-server.devtroncd:5556/dex)","Example":"","Deprecated":"false"},{"Env":"ECR_REPO_NAME_PREFIX","EnvType":"string","EnvValue":"test/","EnvDescription":"Prefix for ECR repo to be created in does not exist","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async installation of gitops application","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable async installation of no-gitops application","Example":"","Deprecated":"false"},{"Env":"ENABLE_NOTIFIER_V2","EnvType":"bool","EnvValue":"false","EnvDescription":"enable notifier v2","Example":"","Deprecated":"false"},{"Env":"EPHEMERAL_SERVER_VERSION_REGEX","EnvType":"string","EnvValue":"v[1-9]\\.\\b(2[3-9]\\|[3-9][0-9])\\b.*","EnvDescription":"ephemeral containers support version regex that is compared with k8sServerVersion","Example":"","Deprecated":"false"},{"Env":"EVENT_URL","EnvType":"string","EnvValue":"http://localhost:3000/notify","EnvDescription":"Notifier service url","Example":"","Deprecated":"false"},{"Env":"EXECUTE_WIRE_NIL_CHECKER","EnvType":"bool","EnvValue":"false","EnvDescription":"checks for any nil pointer in wire.go","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CI_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"To expose CI metrics","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"restart workload retrieval batch size ","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"restart workload retrieval pool size","Example":"","Deprecated":"false"},{"Env":"FORCE_SECURITY_SCANNING","EnvType":"bool","EnvValue":"false","EnvDescription":"By enabling this no one can disable image scaning on ci-pipeline from UI","Example":"","Deprecated":"false"},{"Env":"GITHUB_ORG_NAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITHUB_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITHUB_USERNAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_REPO_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"Prefix for Gitops repo being creation for argocd application","Example":"","Deprecated":"false"},{"Env":"GO_RUNTIME_ENV","EnvType":"string","EnvValue":"production","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Host URL for the grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Namespace for grafana","Example":"","Deprecated":"false"},{"Env":"GRAFANA_ORG_ID","EnvType":"int","EnvValue":"2","EnvDescription":"Org ID for grafana for application metrics","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PASSWORD","EnvType":"string","EnvValue":"prom-operator","EnvDescription":"Password for grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PORT","EnvType":"string","EnvValue":"8090","EnvDescription":"Port for grafana micro-service","Example":"","Deprecated":"false"},{"Env":"GRAFANA_URL","EnvType":"string","EnvValue":"","EnvDescription":"Host URL for the grafana dashboard","Example":"","Deprecated":"false"},{"Env":"GRAFANA_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"Username for grafana ","Example":"","Deprecated":"false"},{"Env":"HIDE_IMAGE_TAGGING_HARD_DELETE","EnvType":"bool","EnvValue":"false","EnvDescription":"Flag to hide the hard delete option in the image tagging service","Example":"","Deprecated":"false"},{"Env":"IGNORE_AUTOCOMPLETE_AUTH_CHECK","EnvType":"bool","EnvValue":"false","EnvDescription":"flag for ignoring auth check in autocomplete apis.","Example":"","Deprecated":"false"},{"Env":"INSTALLED_MODULES","EnvType":"","EnvValue":"","EnvDescription":"List of installed modules given in helm values/yaml are written in cm and used by devtron to know which modules are given","Example":"security.trivy,security.clair","Deprecated":"false"},{"Env":"INSTALLER_CRD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"namespace where Custom Resource Definitions get installed","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_GROUP_NAME","EnvType":"string","EnvValue":"installer.devtron.ai","EnvDescription":"Devtron installer CRD group name, partially deprecated.","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_RESOURCE","EnvType":"string","EnvValue":"installers","EnvDescription":"Devtron installer CRD resource name, partially deprecated","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_VERSION","EnvType":"string","EnvValue":"v1alpha1","EnvDescription":"version of the CRDs. default is v1alpha1","Example":"","Deprecated":"false"},{"Env":"IS_AIR_GAP_ENVIRONMENT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"JwtExpirationTime","EnvType":"int","EnvValue":"120","EnvDescription":"JWT expiration time.","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":"LENS_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"Lens microservice timeout.","Example":"","Deprecated":"false"},{"Env":"LENS_URL","EnvType":"string","EnvValue":"http://lens-milandevtron-service:80","EnvDescription":"Lens micro-service URL","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":"Enables a different logger theme.","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_SESSION_PER_USER","EnvType":"int","EnvValue":"5","EnvDescription":"max no of cluster terminal pods can be created by an user","Example":"","Deprecated":"false"},{"Env":"MODULE_METADATA_API_URL","EnvType":"string","EnvValue":"https://api.devtron.ai/module?name=%s","EnvDescription":"Modules list and meta info will be fetched from this server, that is central api server of devtron.","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":"notification medium","Example":"","Deprecated":"false"},{"Env":"OTEL_COLLECTOR_URL","EnvType":"string","EnvValue":"","EnvDescription":"Opentelemetry URL ","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"","EnvDescription":"App manual sync job parallel tag processing count.","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":"Handles image retrieval from a container repository and triggers subsequent CI processes upon detecting new images.Current default plugin name: Pull Images from Container Repository.","Example":"","Deprecated":"false"},{"Env":"PROPAGATE_EXTRA_LABELS","EnvType":"bool","EnvValue":"false","EnvDescription":"Add additional propagate labels like api.devtron.ai/appName, api.devtron.ai/envName, api.devtron.ai/project along with the user defined ones.","Example":"","Deprecated":"false"},{"Env":"PROXY_SERVICE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"Proxy configuration for micro-service to be accessible on orhcestrator ingress","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":"To restrict the cluster terminal from user having non-super admin acceess","Example":"","Deprecated":"false"},{"Env":"RUNTIME_CONFIG_LOCAL_DEV","EnvType":"LocalDevMode","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable scoped variable option","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_FORMAT","EnvType":"string","EnvValue":"@{{%s}}","EnvDescription":"Its a scope format for varialbe name.","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_HANDLE_PRIMITIVES","EnvType":"bool","EnvValue":"false","EnvDescription":"This describe should we handle primitives or not in scoped variable template parsing.","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":"Regex for scoped variable name that must passed this regex.","Example":"","Deprecated":"false"},{"Env":"SOCKET_DISCONNECT_DELAY_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"The server closes a session when a client receiving connection have not been seen for a while.This delay is configured by this setting. By default the session is closed when a receiving connection wasn't seen for 5 seconds.","Example":"","Deprecated":"false"},{"Env":"SOCKET_HEARTBEAT_SECONDS","EnvType":"int","EnvValue":"25","EnvDescription":"In order to keep proxies and load balancers from closing long running http requests we need to pretend that the connection is active and send a heartbeat packet once in a while. This setting controls how often this is done. By default a heartbeat packet is sent every 25 seconds.","Example":"","Deprecated":"false"},{"Env":"STREAM_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SYSTEM_VAR_PREFIX","EnvType":"string","EnvValue":"DEVTRON_","EnvDescription":"Scoped variable prefix, variable name must have this prefix.","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"default","EnvDescription":"Cluster terminal default namespace","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_INACTIVE_DURATION_IN_MINS","EnvType":"int","EnvValue":"10","EnvDescription":"Timeout for cluster terminal to be inactive","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_STATUS_SYNC_In_SECS","EnvType":"int","EnvValue":"600","EnvDescription":"this is the time interval at which the status of the cluster terminal pod","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":"Timeout for Failed CI build ","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_IN_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"timeout to compute the urls from services and ingress objects of an application","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":"To use the V2 API for listing artifacts in Listing the images in pipeline","Example":"","Deprecated":"false"},{"Env":"USE_CUSTOM_HTTP_TRANSPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_GIT_CLI","EnvType":"bool","EnvValue":"false","EnvDescription":"To enable git cli","Example":"","Deprecated":"false"},{"Env":"USE_RBAC_CREATION_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To use the V2 for RBAC creation","Example":"","Deprecated":"false"},{"Env":"VARIABLE_CACHE_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"This is used to control caching of all the scope variables defined in the system.","Example":"","Deprecated":"false"},{"Env":"VARIABLE_EXPRESSION_REGEX","EnvType":"string","EnvValue":"@{{([^}]+)}}","EnvDescription":"Scoped variable expression regex","Example":"","Deprecated":"false"},{"Env":"WEBHOOK_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"If you want to continue using jenkins for CI then please provide this for authentication of requests","Example":"","Deprecated":"false"}]},{"Category":"GITOPS","Fields":[{"Env":"ACD_CM","EnvType":"string","EnvValue":"argocd-cm","EnvDescription":"Name of the argocd CM","Example":"","Deprecated":"false"},{"Env":"ACD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"To pass the argocd namespace","Example":"","Deprecated":"false"},{"Env":"ACD_PASSWORD","EnvType":"string","EnvValue":"","EnvDescription":"Password for the Argocd (deprecated)","Example":"","Deprecated":"false"},{"Env":"ACD_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"User name for argocd","Example":"","Deprecated":"false"},{"Env":"GITOPS_SECRET_NAME","EnvType":"string","EnvValue":"devtron-gitops-secret","EnvDescription":"devtron-gitops-secret","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS","EnvType":"string","EnvValue":"Deployment,Rollout,StatefulSet,ReplicaSet","EnvDescription":"this holds the list of k8s resource names which support replicas key. this list used in hibernate/un hibernate process","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS_BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"this the batch size to control no of above resources can be parsed in one go to determine hibernate status","Example":"","Deprecated":"false"}]},{"Category":"INFRA_SETUP","Fields":[{"Env":"DASHBOARD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"Dashboard micro-service URL","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"Dashboard micro-service namespace","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_PORT","EnvType":"string","EnvValue":"3000","EnvDescription":"Port for dashboard micro-service","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":"Protocol to connect with git-sensor micro-service","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_SERVICE_CONFIG","EnvType":"string","EnvValue":"{\"loadBalancingPolicy\":\"pick_first\"}","EnvDescription":"git-sensor grpc service config","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"Timeout for getting response from the git-sensor","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_URL","EnvType":"string","EnvValue":"127.0.0.1:7070","EnvDescription":"git-sensor micro-service url ","Example":"","Deprecated":"false"},{"Env":"HELM_CLIENT_URL","EnvType":"string","EnvValue":"127.0.0.1:50051","EnvDescription":"Kubelink micro-service url ","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":"KUBELINK_GRPC_SERVICE_CONFIG","EnvType":"string","EnvValue":"{\"loadBalancingPolicy\":\"round_robin\"}","EnvDescription":"kubelink grpc service config","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":"Database for casbin","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":"Time out for read operation in postgres","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":"Time out for write operation in postgres","Example":"","Deprecated":"false"}]},{"Category":"RBAC","Fields":[{"Env":"ENFORCER_CACHE","EnvType":"bool","EnvValue":"false","EnvDescription":"To Enable enforcer cache.","Example":"","Deprecated":"false"},{"Env":"ENFORCER_CACHE_EXPIRATION_IN_SEC","EnvType":"int","EnvValue":"86400","EnvDescription":"Expiration time (in seconds) for enforcer cache. ","Example":"","Deprecated":"false"},{"Env":"ENFORCER_MAX_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"Maximum batch size for the enforcer.","Example":"","Deprecated":"false"},{"Env":"USE_CASBIN_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"To enable casbin V2 API","Example":"","Deprecated":"false"}]}] \ No newline at end of file diff --git a/env_gen.md b/env_gen.md index 287d84c6d7..3f65efa0c4 100644 --- a/env_gen.md +++ b/env_gen.md @@ -131,11 +131,11 @@ | APP_SYNC_JOB_RESOURCES_OBJ | string | | To pass the resource of app sync | | false | | APP_SYNC_SERVICE_ACCOUNT | string |chart-sync | Service account to be used in app sync Job | | false | | APP_SYNC_SHUTDOWN_WAIT_DURATION | int |120 | | | false | - | ARGO_AUTO_SYNC_ENABLED | bool |true | If enabled all argocd application will have auto sync enabled | | false | + | ARGO_AUTO_SYNC_ENABLED | bool |true | If enabled all argocd application will have auto sync enabled | true | false | | ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT | int |3 | retry argocd app manual sync if the timeline is stuck in ARGOCD_SYNC_INITIATED state for more than this defined time (in mins) | | false | | ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT | int |1 | Delay on retrying the maifest commit the on gitops | | false | - | ARGO_REPO_REGISTER_RETRY_COUNT | int |3 | Argo app registration in argo retries on deployment | | false | - | ARGO_REPO_REGISTER_RETRY_DELAY | int |10 | Argo app registration in argo cd on deployment delay between retry | | false | + | ARGO_REPO_REGISTER_RETRY_COUNT | int |4 | Retry count for registering a GitOps repository to ArgoCD | 3 | false | + | ARGO_REPO_REGISTER_RETRY_DELAY | int |5 | Delay (in Seconds) between the retries for registering a GitOps repository to ArgoCD | 5 | false | | ASYNC_BUILDX_CACHE_EXPORT | bool |false | To enable async container image cache export | | false | | BATCH_SIZE | int |5 | there is feature to get URL's of services/ingresses. so to extract those, we need to parse all the servcie and ingress objects of the application. this BATCH_SIZE flag controls the no of these objects get parsed in one go. | | false | | BLOB_STORAGE_ENABLED | bool |false | | | false | @@ -185,6 +185,9 @@ | FEATURE_RESTART_WORKLOAD_BATCH_SIZE | int |1 | restart workload retrieval batch size | | false | | FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE | int |5 | restart workload retrieval pool size | | false | | FORCE_SECURITY_SCANNING | bool |false | By enabling this no one can disable image scaning on ci-pipeline from UI | | false | + | GITHUB_ORG_NAME | string | | | | false | + | GITHUB_TOKEN | string | | | | false | + | GITHUB_USERNAME | string | | | | false | | GITOPS_REPO_PREFIX | string | | Prefix for Gitops repo being creation for argocd application | | false | | GO_RUNTIME_ENV | string |production | | | false | | GRAFANA_HOST | string |localhost | Host URL for the grafana dashboard | | false | diff --git a/internal/sql/repository/GitOpsConfigRepository.go b/internal/sql/repository/GitOpsConfigRepository.go index 83b68d6eea..c8b6d7cf15 100644 --- a/internal/sql/repository/GitOpsConfigRepository.go +++ b/internal/sql/repository/GitOpsConfigRepository.go @@ -29,6 +29,7 @@ type GitOpsConfigRepository interface { GetAllGitOpsConfig() ([]*GitOpsConfig, error) GetAllGitOpsConfigCount() (int, error) GetGitOpsConfigByProvider(provider string) (*GitOpsConfig, error) + CheckIfGitOpsProviderExist(provider string) (bool, error) GetGitOpsConfigActive() (*GitOpsConfig, error) GetConnection() *pg.DB GetEmailIdFromActiveGitOpsConfig() (string, error) @@ -105,6 +106,13 @@ func (impl *GitOpsConfigRepositoryImpl) GetGitOpsConfigByProvider(provider strin return &model, err } +func (impl *GitOpsConfigRepositoryImpl) CheckIfGitOpsProviderExist(provider string) (bool, error) { + found, err := impl.dbConnection.Model((*GitOpsConfig)(nil)). + Where("provider = ?", provider). + Exists() + return found, err +} + func (impl *GitOpsConfigRepositoryImpl) GetGitOpsConfigActive() (*GitOpsConfig, error) { var model GitOpsConfig err := impl.dbConnection.Model(&model).Where("active = ?", true).Limit(1).Select() diff --git a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go index bbee4e41c8..9678b87979 100644 --- a/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go +++ b/pkg/appStore/installedApp/service/FullMode/deployment/InstalledAppGitOpsService.go @@ -32,10 +32,9 @@ import ( "github.com/google/go-github/github" "github.com/microsoft/azure-devops-go-api/azuredevops" "github.com/xanzy/go-gitlab" - "strconv" - - //"github.com/xanzy/go-gitlab" "net/http" + "strconv" + "strings" ) type InstalledAppGitOpsService interface { @@ -176,7 +175,7 @@ func (impl *FullModeDeploymentServiceImpl) parseGitRepoErrorResponse(err error) impl.Logger.Errorw("no content found while updating git repo gitlab, do auto fix", "error", err) noTargetFound = true } - if err.Error() == git.BITBUCKET_REPO_NOT_FOUND_ERROR { + if strings.Contains(err.Error(), git.BitbucketRepoNotFoundError.Error()) { impl.Logger.Errorw("no content found while updating git repo bitbucket, do auto fix", "error", err) noTargetFound = true } diff --git a/pkg/deployment/gitOps/adapter/adapter.go b/pkg/deployment/gitOps/adapter/adapter.go index d16489bc69..48c06ba350 100644 --- a/pkg/deployment/gitOps/adapter/adapter.go +++ b/pkg/deployment/gitOps/adapter/adapter.go @@ -37,7 +37,7 @@ func GetGitOpsConfigBean(model *repository.GitOpsConfig) *apiGitOpsBean.GitOpsCo BitBucketWorkspaceId: model.BitBucketWorkspaceId, BitBucketProjectKey: model.BitBucketProjectKey, AllowCustomRepository: model.AllowCustomRepository, - EnableTLSVerification: true, + EnableTLSVerification: model.EnableTLSVerification, TLSConfig: &apiBean.TLSConfig{ CaData: model.CaCert, TLSCertData: model.TlsCert, diff --git a/pkg/deployment/gitOps/config/GitOpsConfigReadService.go b/pkg/deployment/gitOps/config/GitOpsConfigReadService.go index 697d0982a4..d60c085879 100644 --- a/pkg/deployment/gitOps/config/GitOpsConfigReadService.go +++ b/pkg/deployment/gitOps/config/GitOpsConfigReadService.go @@ -19,7 +19,6 @@ package config import ( "errors" "fmt" - bean3 "github.com/devtron-labs/devtron/api/bean" bean2 "github.com/devtron-labs/devtron/api/bean/gitOps" "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/sql/repository" @@ -27,6 +26,8 @@ import ( "github.com/devtron-labs/devtron/pkg/auth/user" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/adapter" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config/bean" + gitAdapter "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/adapter" + gitBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" moduleBean "github.com/devtron-labs/devtron/pkg/module/bean" moduleRead "github.com/devtron-labs/devtron/pkg/module/read" moduleErr "github.com/devtron-labs/devtron/pkg/module/read/error" @@ -49,6 +50,7 @@ type GitOpsConfigReadService interface { GetConfiguredGitOpsCount() (int, error) GetGitOpsProviderByRepoURL(gitRepoUrl string) (*bean2.GitOpsConfigDto, error) GetGitOpsById(id int) (*bean2.GitOpsConfigDto, error) + GetGitConfig() (*gitBean.GitConfig, error) } type GitOpsConfigReadServiceImpl struct { @@ -211,25 +213,14 @@ func (impl *GitOpsConfigReadServiceImpl) GetGitOpsById(id int) (*bean2.GitOpsCon impl.logger.Errorw("error, GetGitOpsConfigById", "id", id, "err", err) return nil, err } - config := &bean2.GitOpsConfigDto{ - Id: model.Id, - Provider: model.Provider, - GitHubOrgId: model.GitHubOrgId, - GitLabGroupId: model.GitLabGroupId, - Active: model.Active, - Token: model.Token, - Host: model.Host, - Username: model.Username, - UserId: model.CreatedBy, - AzureProjectName: model.AzureProject, - BitBucketWorkspaceId: model.BitBucketWorkspaceId, - BitBucketProjectKey: model.BitBucketProjectKey, - AllowCustomRepository: model.AllowCustomRepository, - TLSConfig: &bean3.TLSConfig{ - CaData: model.CaCert, - TLSCertData: model.TlsCert, - TLSKeyData: model.TlsKey, - }, - } - return config, err + return adapter.GetGitOpsConfigBean(model), err +} + +func (impl *GitOpsConfigReadServiceImpl) GetGitConfig() (*gitBean.GitConfig, error) { + gitOpsConfig, err := impl.GetGitOpsConfigActive() + if err != nil { + impl.logger.Errorw("error while fetching gitops config", "err", err) + return nil, err + } + return gitAdapter.ConvertGitOpsConfigToGitConfig(gitOpsConfig), err } diff --git a/pkg/deployment/gitOps/git/GitFactory.go b/pkg/deployment/gitOps/git/GitFactory.go index 851ed3415c..301a93682f 100644 --- a/pkg/deployment/gitOps/git/GitFactory.go +++ b/pkg/deployment/gitOps/git/GitFactory.go @@ -18,11 +18,13 @@ package git import ( "crypto/tls" + "errors" "fmt" "github.com/devtron-labs/devtron/api/bean/gitOps" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/adapter" "github.com/devtron-labs/devtron/util" + "github.com/go-pg/pg" "github.com/xanzy/go-gitlab" "go.uber.org/zap" "time" @@ -34,24 +36,27 @@ type GitFactory struct { logger *zap.SugaredLogger } -func (factory *GitFactory) Reload(gitOpsConfigReadService config.GitOpsConfigReadService) error { - var err error +func (factory *GitFactory) Reload(gitOpsConfigReadService config.GitOpsConfigReadService) (err error) { start := time.Now() defer func() { util.TriggerGitOpsMetrics("Reload", "GitService", start, err) }() factory.logger.Infow("reloading gitops details") - cfg, err := GetGitConfig(gitOpsConfigReadService) - if err != nil { + gitConfig, err := gitOpsConfigReadService.GetGitConfig() + if err != nil && !errors.Is(err, pg.ErrNoRows) { + factory.logger.Errorw("error in getting gitops config", "err", err) return err + } else if errors.Is(err, pg.ErrNoRows) || gitConfig == nil { + factory.logger.Warn("no gitops config found, gitops will not work") + return nil } - factory.GitOpsHelper.SetAuth(cfg.GetAuth()) - client, err := NewGitOpsClient(cfg, factory.logger, factory.GitOpsHelper) + factory.GitOpsHelper.SetAuth(gitConfig.GetAuth()) + client, err := NewGitOpsClient(gitConfig, factory.logger, factory.GitOpsHelper) if err != nil { return err } factory.Client = client - factory.logger.Infow(" gitops details reload success") + factory.logger.Infow("gitops details reload success") return nil } @@ -78,7 +83,7 @@ func (factory *GitFactory) GetGitLabGroupPath(gitOpsConfig *gitOps.GitOpsConfigD } group, _, err := gitLabClient.Groups.GetGroup(gitOpsConfig.GitLabGroupId, &gitlab.GetGroupOptions{}) if err != nil { - factory.logger.Errorw("error in fetching gitlab group name", "err", err, "gitLab groupID", gitOpsConfig.GitLabGroupId) + factory.logger.Errorw("error in fetching gitlab group name", "gitLab groupID", gitOpsConfig.GitLabGroupId, "err", err) return "", err } if group == nil { @@ -96,10 +101,14 @@ func (factory *GitFactory) NewClientForValidation(gitOpsConfig *gitOps.GitOpsCon }() cfg := adapter.ConvertGitOpsConfigToGitConfig(gitOpsConfig) //factory.GitOpsHelper.SetAuth(cfg.GetAuth()) - gitOpsHelper := NewGitOpsHelperImpl(cfg.GetAuth(), factory.logger, cfg.GetTLSConfig(), gitOpsConfig.EnableTLSVerification) - + gitOpsHelper, err := NewGitOpsHelperImpl(cfg.GetAuth(), factory.logger, cfg.GetTLSConfig(), gitOpsConfig.EnableTLSVerification) + if err != nil { + factory.logger.Errorw("error in creating gitOps helper", "gitProvider", cfg.GitProvider, "err", err) + return nil, gitOpsHelper, err + } client, err := NewGitOpsClient(cfg, factory.logger, gitOpsHelper) if err != nil { + factory.logger.Errorw("error in creating gitOps client", "gitProvider", cfg.GitProvider, "err", err) return client, gitOpsHelper, err } @@ -109,18 +118,31 @@ func (factory *GitFactory) NewClientForValidation(gitOpsConfig *gitOps.GitOpsCon } func NewGitFactory(logger *zap.SugaredLogger, gitOpsConfigReadService config.GitOpsConfigReadService) (*GitFactory, error) { - cfg, err := GetGitConfig(gitOpsConfigReadService) + gitFactory := &GitFactory{ + logger: logger, + } + gitConfig, err := gitOpsConfigReadService.GetGitConfig() + if err != nil && !errors.Is(err, pg.ErrNoRows) { + logger.Errorw("error in getting gitops config", "err", err) + return gitFactory, err + } else if errors.Is(err, pg.ErrNoRows) || gitConfig == nil { + logger.Warn("no gitops config found, gitops will not work") + return gitFactory, nil + } + gitOpsHelper, err := NewGitOpsHelperImpl(gitConfig.GetAuth(), logger, gitConfig.GetTLSConfig(), gitConfig.EnableTLSVerification) if err != nil { - return nil, err + logger.Errorw("error in creating gitOps helper", "gitProvider", gitConfig.GitProvider, "err", err) + // error handling is skipped intentionally here, otherwise orchestration will not work } - gitOpsHelper := NewGitOpsHelperImpl(cfg.GetAuth(), logger, cfg.GetTLSConfig(), cfg.EnableTLSVerification) - client, err := NewGitOpsClient(cfg, logger, gitOpsHelper) + gitFactory.GitOpsHelper = gitOpsHelper + client, err := NewGitOpsClient(gitConfig, logger, gitOpsHelper) if err != nil { - logger.Errorw("error in creating gitOps client", "err", err, "gitProvider", cfg.GitProvider) + logger.Errorw("error in creating gitOps client", "gitProvider", gitConfig.GitProvider, "err", err) + // error handling is skipped intentionally here, otherwise orchestration will not work + } + if client == nil { + client = &UnimplementedGitOpsClient{} } - return &GitFactory{ - Client: client, - logger: logger, - GitOpsHelper: gitOpsHelper, - }, nil + gitFactory.Client = client + return gitFactory, nil } diff --git a/pkg/deployment/gitOps/git/GitHubClient_test.go b/pkg/deployment/gitOps/git/GitHubClient_test.go new file mode 100644 index 0000000000..8de85c1fe1 --- /dev/null +++ b/pkg/deployment/gitOps/git/GitHubClient_test.go @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2024. Devtron Inc. + */ + +package git + +import ( + "context" + "crypto/tls" + "fmt" + "github.com/caarlos0/env" + "github.com/devtron-labs/devtron/api/bean" + apiBean "github.com/devtron-labs/devtron/api/bean/gitOps" + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/commandManager" + validationBean "github.com/devtron-labs/devtron/pkg/deployment/gitOps/validation/bean" + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/util/rand" + "slices" + "strings" + "testing" + "time" +) + +func TestGitHubProvider(t *testing.T) { + t.Run("GitHubClient Tests", func(t *testing.T) { + t.Run("CreateRepository", newGithubTestClient(t).CreateRepositoryByClient) + t.Run("CommitValues", newGithubTestClient(t).CommitValuesByClient) + }) +} + +// gitHubTestConfig holds the configuration for GitHub tests +type gitHubTestConfig struct { + GitHubUsername string `env:"GITHUB_USERNAME"` + GitHubToken string `env:"GITHUB_TOKEN"` + GitHubOrgName string `env:"GITHUB_ORG_NAME"` +} + +func newGitHubTestConfig() (*gitHubTestConfig, error) { + cfg := &gitHubTestConfig{} + err := env.Parse(cfg) + return cfg, err +} + +func (github *gitHubTestConfig) getProvider() string { + return GITHUB_PROVIDER +} + +func (github *gitHubTestConfig) getHost() string { + return "https://github.com/" +} + +func (github *gitHubTestConfig) getOrg() string { + return github.GitHubOrgName +} + +func (github *gitHubTestConfig) getUsername() string { + return github.GitHubUsername +} + +func (github *gitHubTestConfig) getToken() string { + return github.GitHubToken +} + +func (github *gitHubTestConfig) getBasicAuth() *commandManager.BasicAuth { + return &commandManager.BasicAuth{ + Username: github.getUsername(), + Password: github.getToken(), + } +} + +func getGitHubTestHttpClient(t *testing.T) (GitHubClient, *GitOpsHelper, *gitHubTestConfig) { + logger, err := util.NewSugardLogger() + if err != nil { + t.Fatalf("failed to create logger: %v", err) + } + githubCfg, err := newGitHubTestConfig() + if err != nil { + t.Fatalf("failed to load GitHub test config: %v", err) + } + gitService, err := NewGitOpsHelperImpl( + githubCfg.getBasicAuth(), logger, + &bean.TLSConfig{}, false) + if err != nil { + t.Fatalf("failed to create GitOpsHelperImpl: %v", err) + } + githubClient, err := NewGithubClient( + githubCfg.getHost(), githubCfg.getToken(), githubCfg.getOrg(), + logger, gitService, &tls.Config{}) + if err != nil { + t.Fatalf("failed to create GitHub client: %v", err) + } + return githubClient, gitService, githubCfg +} + +type githubTestClient struct { + gitHubClient GitHubClient + gitOpsHelper *GitOpsHelper + config *gitHubTestConfig +} + +func newGithubTestClient(t *testing.T) *githubTestClient { + gitHubClient, gitOpsHelper, config := getGitHubTestHttpClient(t) + return &githubTestClient{ + gitHubClient: gitHubClient, + gitOpsHelper: gitOpsHelper, + config: config, + } +} + +// GitHubClient Tests ----------------------------- +func (impl *githubTestClient) CreateRepositoryByClient(t *testing.T) { + // t.SkipNow() + tests := []struct { + name string + getGitOpsConfigDto func(*gitHubTestConfig) *apiBean.GitOpsConfigDto + wantIsNew bool + wantIsEmpty bool + wantErrCount int + }{ + { + name: "valid case - create new repository", + getGitOpsConfigDto: func(validGithubCfg *gitHubTestConfig) *apiBean.GitOpsConfigDto { + return &apiBean.GitOpsConfigDto{ + GitRepoName: "test-repo-" + strings.ToLower(rand.SafeEncodeString(rand.String(5))), + Description: "Test repository for GitHub client", + Provider: validGithubCfg.getProvider(), + Username: validGithubCfg.getUsername(), + Token: validGithubCfg.getToken(), + GitHubOrgId: validGithubCfg.getOrg(), + Host: validGithubCfg.getHost(), + Active: true, + UserEmailId: fmt.Sprintf("%s@devtron.ai", validGithubCfg.getUsername()), + UserId: 1, + } + }, + wantIsNew: true, + wantIsEmpty: false, + wantErrCount: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gitOpsConfigDTO := tt.getGitOpsConfigDto(impl.config) + // Create a new repository + _, gotIsNew, gotIsEmpty, detailedErrorGitOpsConfigActions := impl.gitHubClient.CreateRepository(context.Background(), gitOpsConfigDTO) + // Clean up by deleting the repository + defer func() { + if slices.Contains(detailedErrorGitOpsConfigActions.SuccessfulStages, validationBean.CreateRepoStage) { + err := impl.gitHubClient.DeleteRepository(gitOpsConfigDTO) + assert.NoError(t, err, "DeleteRepository() error = %v", err) + } + }() + errorCount := len(detailedErrorGitOpsConfigActions.StageErrorMap) + assert.Equalf(t, tt.wantErrCount, errorCount, "CreateRepository() error count = %v, want 0", errorCount) + if tt.wantErrCount == 0 { + assert.Equalf(t, tt.wantIsNew, gotIsNew, "CreateRepository() gotIsNew = %v, want %v", gotIsNew, tt.wantIsNew) + assert.Equalf(t, tt.wantIsEmpty, gotIsEmpty, "CreateRepository() gotIsEmpty = %v, want %v", gotIsEmpty, tt.wantIsEmpty) + } + // Create the same repository again to check if it is not created again + _, gotIsNew, gotIsEmpty, detailedErrorGitOpsConfigActions = impl.gitHubClient.CreateRepository(context.Background(), gitOpsConfigDTO) + errorCount = len(detailedErrorGitOpsConfigActions.StageErrorMap) + assert.Equalf(t, tt.wantErrCount, errorCount, "CreateRepository() error count = %v, want 0", errorCount) + if tt.wantErrCount == 0 { + assert.Equalf(t, false, gotIsNew, "CreateRepository() gotIsNew = %v, want %v", gotIsNew, false) + // If the repository just created, GitHub API calculates the size hourly, + // So it may not be empty immediately, + // Hence we skip the assertion for gotIsEmpty in the second call. + // assert.Equalf(t, false, gotIsEmpty, "CreateRepository() gotIsEmpty = %v, want %v", gotIsEmpty, false) + } + }) + } +} + +func (impl *githubTestClient) CommitValuesByClient(t *testing.T) { + // t.SkipNow() + gitOpsConfigDTO := &apiBean.GitOpsConfigDto{ + GitRepoName: "test-repo-" + strings.ToLower(rand.SafeEncodeString(rand.String(5))), + Description: "Test repository for GitHub client", + Provider: impl.config.getProvider(), + Username: impl.config.getUsername(), + Token: impl.config.getToken(), + GitHubOrgId: impl.config.getOrg(), + Host: impl.config.getHost(), + Active: true, + UserEmailId: fmt.Sprintf("%s@devtron.ai", impl.config.getUsername()), + UserId: 1, + } + repoUrl, isNew, isEmpty, detailedErrorGitOpsConfigActions := impl.gitHubClient.CreateRepository(context.Background(), gitOpsConfigDTO) + // Clean up by deleting the repository + defer func() { + if slices.Contains(detailedErrorGitOpsConfigActions.SuccessfulStages, validationBean.CreateRepoStage) { + err := impl.gitHubClient.DeleteRepository(gitOpsConfigDTO) + assert.NoError(t, err, "DeleteRepository() error = %v", err) + } + }() + // Assert that the repository was created successfully + assert.Equal(t, true, isNew) + // Assert that the repository is not empty as we commit a README file + assert.Equal(t, false, isEmpty) + // Assert that the repository URL is not empty + assert.NotEmpty(t, repoUrl) + // Assert that there are no errors in the detailed error map + assert.Empty(t, detailedErrorGitOpsConfigActions.StageErrorMap) + + // Test case for committing values to the repository + tests := []struct { + name string + chartConfig func(gitOpsConfigDTO *apiBean.GitOpsConfigDto, repoUrl string) *ChartConfig + assertError assert.ErrorAssertionFunc + }{ + { + name: "valid commit", + chartConfig: func(gitOpsConfigDTO *apiBean.GitOpsConfigDto, repoUrl string) *ChartConfig { + return &ChartConfig{ + FileName: "README.md", + FileContent: `## Description: +This is a test chart for testing GitHub client commit functionality. +Signature: @devtron-labs`, + ReleaseMessage: "test commit", + ChartRepoName: gitOpsConfigDTO.GitRepoName, + TargetRevision: "master", + UseDefaultBranch: true, + UserName: gitOpsConfigDTO.Username, + UserEmailId: gitOpsConfigDTO.UserEmailId, + } + }, + assertError: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + chartConfig := tt.chartConfig(gitOpsConfigDTO, repoUrl) + commitHash, commitTime, err := impl.gitHubClient.CommitValues(context.Background(), chartConfig, gitOpsConfigDTO, false) + if !tt.assertError(t, err, "CommitValues() error = %v", err) { + return + } + assert.NotEmpty(t, commitHash) + assert.NotEqual(t, time.Time{}, commitTime) + // Verify the commit by checking the file content + + }) + } +} + +// ------------------------------------------------ diff --git a/pkg/deployment/gitOps/git/GitOperationService.go b/pkg/deployment/gitOps/git/GitOperationService.go index 2f96fc0333..480d29abab 100644 --- a/pkg/deployment/gitOps/git/GitOperationService.go +++ b/pkg/deployment/gitOps/git/GitOperationService.go @@ -43,7 +43,9 @@ import ( type GitOperationService interface { CreateGitRepositoryForDevtronApp(ctx context.Context, gitOpsRepoName string, targetRevision string, userId int32) (chartGitAttribute *commonBean.ChartGitAttribute, err error) - CreateReadmeInGitRepo(ctx context.Context, gitOpsRepoName string, targetRevision string, userId int32) error + // CreateFirstCommitOnHead - creates the first commit on the head of the git repository (mostly empty). + // To register the git repository in ArgoCD, there should be a commit HEAD on the default branch. + CreateFirstCommitOnHead(ctx context.Context, gitOpsRepoName string, userId int32) error GitPull(clonedDir string, repoUrl string, targetRevision string) error CommitValues(ctx context.Context, chartGitAttr *ChartConfig) (commitHash string, commitTime time.Time, err error) @@ -210,7 +212,7 @@ func (impl *GitOperationServiceImpl) updateRepoAndPushAllChanges(ctx context.Con return commit, nil } -func (impl *GitOperationServiceImpl) CreateReadmeInGitRepo(ctx context.Context, gitOpsRepoName string, targetRevision string, userId int32) error { +func (impl *GitOperationServiceImpl) CreateFirstCommitOnHead(ctx context.Context, gitOpsRepoName string, userId int32) error { userEmailId, userName := impl.gitOpsConfigReadService.GetUserEmailIdAndNameForGitOpsCommit(userId) gitOpsConfig, err := impl.gitOpsConfigReadService.GetGitOpsConfigActive() if err != nil { @@ -222,11 +224,10 @@ func (impl *GitOperationServiceImpl) CreateReadmeInGitRepo(ctx context.Context, gitOpsConfig.UserEmailId = userEmailId gitOpsConfig.Username = userName gitOpsConfig.GitRepoName = gitOpsRepoName - gitOpsConfig.TargetRevision = targetRevision } - _, err = impl.gitFactory.Client.CreateReadme(ctx, gitOpsConfig) + _, err = impl.gitFactory.Client.CreateFirstCommitOnHead(ctx, gitOpsConfig) if err != nil { - impl.logger.Errorw("error in creating readme", "err", err, "gitOpsRepoName", gitOpsRepoName, "userId", userId) + impl.logger.Errorw("error in creating readme", "gitOpsRepoName", gitOpsRepoName, "userId", userId, "err", err) return err } return nil @@ -299,7 +300,7 @@ func (impl *GitOperationServiceImpl) CreateRepository(ctx context.Context, dto * repoUrl, isNew, isEmpty, detailedError := impl.gitFactory.Client.CreateRepository(ctx, dto) for _, err := range detailedError.StageErrorMap { if err != nil { - impl.logger.Errorw("error in creating git project", "err", err, "req", dto) + impl.logger.Errorw("error in creating git project", "req", dto, "err", err) return "", false, false, err } } @@ -337,12 +338,12 @@ func (impl *GitOperationServiceImpl) PushChartToGitOpsRepoForHelmApp(ctx context } err = impl.addConfigFileToChart(requirementsConfig, dir, clonedDir) if err != nil { - impl.logger.Errorw("error in adding requirements.yaml to chart", "err", err, "appName", pushChartToGitRequest.AppName) + impl.logger.Errorw("error in adding requirements.yaml to chart", "appName", pushChartToGitRequest.AppName, "err", err) return nil, "", err } err = impl.addConfigFileToChart(valuesConfig, dir, clonedDir) if err != nil { - impl.logger.Errorw("error in adding values.yaml to chart", "err", err, "appName", pushChartToGitRequest.AppName) + impl.logger.Errorw("error in adding values.yaml to chart", "appName", pushChartToGitRequest.AppName, "err", err) return nil, "", err } userEmailId, userName := impl.gitOpsConfigReadService.GetUserEmailIdAndNameForGitOpsCommit(pushChartToGitRequest.UserId) @@ -352,7 +353,7 @@ func (impl *GitOperationServiceImpl) PushChartToGitOpsRepoForHelmApp(ctx context impl.logger.Warn("re-trying, taking pull and then push again") err = impl.GitPull(clonedDir, pushChartToGitRequest.RepoURL, pushChartToGitRequest.TargetRevision) if err != nil { - impl.logger.Errorw("error in git pull", "err", err, "appName", gitOpsChartLocation) + impl.logger.Errorw("error in git pull", "appName", gitOpsChartLocation, "err", err) return nil, "", err } err = dirCopy.Copy(pushChartToGitRequest.TempChartRefDir, dir) diff --git a/pkg/deployment/gitOps/git/GitOpsClient.go b/pkg/deployment/gitOps/git/GitOpsClient.go index dc622edd4b..5b80136515 100644 --- a/pkg/deployment/gitOps/git/GitOpsClient.go +++ b/pkg/deployment/gitOps/git/GitOpsClient.go @@ -20,10 +20,8 @@ import ( "context" "crypto/tls" "github.com/devtron-labs/devtron/api/bean/gitOps" - "github.com/devtron-labs/devtron/pkg/deployment/gitOps/config" "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/bean" "github.com/devtron-labs/devtron/util" - "github.com/go-pg/pg" "go.uber.org/zap" "time" ) @@ -34,40 +32,9 @@ type GitOpsClient interface { GetRepoUrl(config *gitOps.GitOpsConfigDto) (repoUrl string, isRepoEmpty bool, err error) DeleteRepository(config *gitOps.GitOpsConfigDto) error CreateReadme(ctx context.Context, config *gitOps.GitOpsConfigDto) (string, error) -} - -func GetGitConfig(gitOpsConfigReadService config.GitOpsConfigReadService) (*bean.GitConfig, error) { - gitOpsConfig, err := gitOpsConfigReadService.GetGitOpsConfigActive() - if err != nil && err != pg.ErrNoRows { - return nil, err - } else if err == pg.ErrNoRows { - // adding this block for backward compatibility,TODO: remove in next iteration - // cfg := &GitConfig{} - // err := env.Parse(cfg) - // return cfg, err - return &bean.GitConfig{}, nil - } - - if gitOpsConfig == nil || gitOpsConfig.Id == 0 { - return nil, err - } - cfg := &bean.GitConfig{ - GitlabGroupId: gitOpsConfig.GitLabGroupId, - GitToken: gitOpsConfig.Token, - GitUserName: gitOpsConfig.Username, - GithubOrganization: gitOpsConfig.GitHubOrgId, - GitProvider: gitOpsConfig.Provider, - GitHost: gitOpsConfig.Host, - AzureToken: gitOpsConfig.Token, - AzureProject: gitOpsConfig.AzureProjectName, - BitbucketWorkspaceId: gitOpsConfig.BitBucketWorkspaceId, - BitbucketProjectKey: gitOpsConfig.BitBucketProjectKey, - EnableTLSVerification: gitOpsConfig.EnableTLSVerification, - TLSCert: gitOpsConfig.TLSConfig.TLSCertData, - TLSKey: gitOpsConfig.TLSConfig.TLSKeyData, - CaCert: gitOpsConfig.TLSConfig.CaData, - } - return cfg, err + // CreateFirstCommitOnHead creates a commit on the HEAD of the repository, used for initializing the repository. + // It is used when the repository is empty and needs an initial commit. + CreateFirstCommitOnHead(ctx context.Context, config *gitOps.GitOpsConfigDto) (string, error) } func NewGitOpsClient(config *bean.GitConfig, logger *zap.SugaredLogger, gitOpsHelper *GitOpsHelper) (GitOpsClient, error) { @@ -95,7 +62,7 @@ func NewGitOpsClient(config *bean.GitConfig, logger *zap.SugaredLogger, gitOpsHe gitBitbucketClient := NewGitBitbucketClient(config.GitUserName, config.GitToken, config.GitHost, logger, gitOpsHelper, tlsConfig) return gitBitbucketClient, nil } else { - logger.Errorw("no gitops config provided, gitops will not work ") - return nil, nil + logger.Warn("no gitops config provided, gitops will not work") + return &UnimplementedGitOpsClient{}, nil } } diff --git a/pkg/deployment/gitOps/git/GitOpsHelper.go b/pkg/deployment/gitOps/git/GitOpsHelper.go index 2c9b51b8d6..390b527664 100644 --- a/pkg/deployment/gitOps/git/GitOpsHelper.go +++ b/pkg/deployment/gitOps/git/GitOpsHelper.go @@ -23,6 +23,7 @@ import ( apiGitOpsBean "github.com/devtron-labs/devtron/api/bean/gitOps" git "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/commandManager" "github.com/devtron-labs/devtron/util" + "github.com/devtron-labs/devtron/util/sliceUtil" "go.opentelemetry.io/otel" "os" "path/filepath" @@ -42,14 +43,15 @@ type GitOpsHelper struct { isTlsEnabled bool } -func NewGitOpsHelperImpl(auth *git.BasicAuth, logger *zap.SugaredLogger, tlsConfig *bean.TLSConfig, isTlsEnabled bool) *GitOpsHelper { - return &GitOpsHelper{ +func NewGitOpsHelperImpl(auth *git.BasicAuth, logger *zap.SugaredLogger, tlsConfig *bean.TLSConfig, isTlsEnabled bool) (*GitOpsHelper, error) { + gitOpsHelper := &GitOpsHelper{ Auth: auth, logger: logger, gitCommandManager: git.NewGitCommandManager(logger), tlsConfig: tlsConfig, isTlsEnabled: isTlsEnabled, } + return gitOpsHelper, nil } func (impl *GitOpsHelper) SetAuth(auth *git.BasicAuth) { @@ -70,29 +72,55 @@ func (impl *GitOpsHelper) Clone(url, targetDir, targetRevision string) (clonedDi defer func() { util.TriggerGitOpsMetrics("Clone", "GitService", start, err) }() + var gitCtx git.GitContext + gitCtx, clonedDir, err = impl.cloneAndFetch(url, targetDir) + if err != nil { + impl.logger.Errorw("error in git clone and fetch", "url", url, "targetDir", targetDir, "err", err) + return clonedDir, err + } + err = impl.pullFromTargetRevision(gitCtx, clonedDir, targetRevision) + if err != nil { + impl.logger.Errorw("error in git pull from target revision", "clonedDir", clonedDir, "targetRevision", targetRevision, "err", err) + return clonedDir, err + } + return clonedDir, nil +} + +func (impl *GitOpsHelper) cloneAndFetch(url, targetDir string) (ctx git.GitContext, clonedDir string, err error) { impl.logger.Debugw("git checkout ", "url", url, "dir", targetDir) clonedDir = filepath.Join(GIT_WORKING_DIR, targetDir) - - ctx := git.BuildGitContext(context.Background()).WithCredentials(impl.Auth). + ctx = git.BuildGitContext(context.Background()).WithCredentials(impl.Auth). WithTLSData(impl.tlsConfig.CaData, impl.tlsConfig.TLSKeyData, impl.tlsConfig.TLSCertData, impl.isTlsEnabled) err = impl.init(ctx, clonedDir, url, false) if err != nil { - return "", err + return ctx, clonedDir, err } _, errMsg, err := impl.gitCommandManager.Fetch(ctx, clonedDir) - if err == nil && errMsg == "" { - impl.logger.Debugw("git fetch completed, pulling master branch data from remote origin") - _, errMsg, err := impl.pullFromBranch(ctx, clonedDir, targetRevision) - if err != nil { - impl.logger.Errorw("error on git pull", "err", err) - return errMsg, err - } - } if errMsg != "" { impl.logger.Errorw("error in git fetch command", "errMsg", errMsg, "err", err) - return "", fmt.Errorf(errMsg) + return ctx, clonedDir, fmt.Errorf(errMsg) + } else if err != nil { + impl.logger.Errorw("error in git fetch command", "clonedDir", clonedDir, "url", url, "err", err) + return ctx, clonedDir, fmt.Errorf("error in git fetch command: %v", err) } - return clonedDir, nil + impl.logger.Debugw("git fetch completed, pulling master branch data from remote origin") + return ctx, clonedDir, nil +} + +func (impl *GitOpsHelper) pullFromTargetRevision(ctx git.GitContext, clonedDir, targetRevision string) (err error) { + branch, isEmptyRepo, err := impl.getSanitisedTargetRevision(ctx, clonedDir, targetRevision) + if err != nil { + impl.logger.Errorw("no branch found in git repo", "clonedDir", clonedDir, "targetRevision", targetRevision, "err", err) + return err + } + if !isEmptyRepo { + _, errMsg, err := impl.pullFromBranch(ctx, clonedDir, branch) + if err != nil { + impl.logger.Errorw("error on git pull", "clonedDir", clonedDir, "branch", branch, "errMsg", errMsg, "err", err) + return err + } + } + return nil } func (impl *GitOpsHelper) Pull(repoRoot, targetRevision string) (err error) { @@ -126,12 +154,7 @@ func (impl *GitOpsHelper) CommitAndPushAllChanges(ctx context.Context, repoRoot, return commitHash, nil } -func (impl *GitOpsHelper) pullFromBranch(ctx git.GitContext, rootDir, targetRevision string) (string, string, error) { - branch, err := impl.getBranch(ctx, rootDir, targetRevision) - if err != nil || branch == "" { - impl.logger.Warnw("no branch found in git repo", "rootDir", rootDir) - return "", "", err - } +func (impl *GitOpsHelper) pullFromBranch(ctx git.GitContext, rootDir, branch string) (string, string, error) { start := time.Now() response, errMsg, err := impl.gitCommandManager.PullCli(ctx, rootDir, branch) if err != nil { @@ -163,35 +186,85 @@ func (impl *GitOpsHelper) init(ctx git.GitContext, rootDir string, remoteUrl str return impl.gitCommandManager.AddRepo(ctx, rootDir, remoteUrl, isBare) } -func (impl *GitOpsHelper) getBranch(ctx git.GitContext, rootDir, targetRevision string) (string, error) { +func (impl *GitOpsHelper) getRemoteBranchList(ctx git.GitContext, rootDir string) ([]string, error) { + validBranches := make([]string, 0) response, errMsg, err := impl.gitCommandManager.ListBranch(ctx, rootDir) if err != nil { impl.logger.Errorw("error on git pull", "response", response, "errMsg", errMsg, "err", err) - return response, err + return validBranches, err } branches := strings.Split(response, "\n") - impl.logger.Infow("total branch available in git repo", "branch length", len(branches)) - branch := impl.getDefaultBranch(branches, targetRevision) + validBranches = sliceUtil.Filter(validBranches, branches, func(item string) bool { + return len(item) != 0 + }) + impl.logger.Infow("total branch available in git repo", "branch length", len(validBranches), "branches", validBranches) + return validBranches, nil +} + +func (impl *GitOpsHelper) getSanitisedTargetRevision(ctx git.GitContext, rootDir, targetRevision string) (string, bool, error) { + validBranches, err := impl.getRemoteBranchList(ctx, rootDir) + if err != nil { + impl.logger.Errorw("error in getting remote branch list", "rootDir", rootDir, "targetRevision", targetRevision, "err", err) + return "", false, err + } + branch, isEmptyRepo, err := impl.getTargetRevision(ctx, rootDir, validBranches, targetRevision) + if err != nil { + impl.logger.Errorw("error in getting default branch", "branches", validBranches, "targetRevision", targetRevision, "err", err) + return "", isEmptyRepo, err + } if strings.HasPrefix(branch, "origin/") { branch = strings.TrimPrefix(branch, "origin/") } - return branch, nil + return branch, isEmptyRepo, nil } -func (impl *GitOpsHelper) getDefaultBranch(branches []string, targetRevision string) (branch string) { +// getDefaultBranch returns the default branch of the git repository. +// - CASE 1: If the git repository has some branches, it will return the default branch. +// - CASE 2: If the git repository has no branches, it will return the current branch. +func (impl *GitOpsHelper) getDefaultBranch(ctx git.GitContext, rootDir string, branches []string) (branch string, isEmptyRepo bool, err error) { + // if git repo has some branch, take pull of the default branch. + // but eventually commit will push into TargetRevision branch. + if len(branches) != 0 { + // if no branch found then try to get the default branch from git + impl.logger.Debugw("no branch found in git repo, trying to get default branch", "branches", branches) + response, errMsg, err := impl.gitCommandManager.GetDefaultBranch(ctx, rootDir) + if err == nil && strings.TrimSpace(response) != "" { + branch = strings.TrimSpace(response) + impl.logger.Debugw("default branch found in git repo", "branch", branch) + return branch, isEmptyRepo, nil + } + impl.logger.Errorw("error on git pull", "response", response, "errMsg", errMsg, "err", err) + // if error is not nil, then it means no default branch found in git repo. + // so we will return the first branch as default branch. + + // As the origin/HEAD is found in the branches list, + // we will consider it as an empty repository. + isEmptyRepo = true + impl.logger.Warnw("no default branch found in git repo, returning first branch", "branches", branches) + branch = strings.TrimSpace(branches[0]) + return branch, isEmptyRepo, nil + } + isEmptyRepo = true + impl.logger.Warnw("no branch found in git repo, returning default branch", "branch", util.GetDefaultTargetRevision()) + branch = util.GetDefaultTargetRevision() + return branch, isEmptyRepo, err +} + +func (impl *GitOpsHelper) getTargetRevision(ctx git.GitContext, rootDir string, branches []string, targetRevision string) (branch string, isEmptyRepo bool, err error) { // the preferred branch is bean.TargetRevisionMaster for _, item := range branches { if len(targetRevision) != 0 && item == targetRevision { - return targetRevision + return targetRevision, isEmptyRepo, nil } else if util.IsDefaultTargetRevision(item) { - return util.GetDefaultTargetRevision() + return util.GetDefaultTargetRevision(), isEmptyRepo, nil } } - // if git repo has some branch take pull of the first branch, but eventually proxy chart will push into master branch - if len(branches) != 0 { - return strings.TrimSpace(branches[0]) + branch, isEmptyRepo, err = impl.getDefaultBranch(ctx, rootDir, branches) + if err != nil { + impl.logger.Errorw("error in getting default branch", "branches", branches, "targetRevision", targetRevision, "err", err) + return "", isEmptyRepo, err } - return util.GetDefaultTargetRevision() + return branch, isEmptyRepo, err } /* diff --git a/pkg/deployment/gitOps/git/GitServiceAzure.go b/pkg/deployment/gitOps/git/GitServiceAzure.go index 323196e220..6d042609aa 100644 --- a/pkg/deployment/gitOps/git/GitServiceAzure.go +++ b/pkg/deployment/gitOps/git/GitServiceAzure.go @@ -185,6 +185,10 @@ func (impl GitAzureClient) CreateRepository(ctx context.Context, config *bean2.G return *operationReference.WebUrl, true, isEmpty, detailedErrorGitOpsConfigActions } +func (impl GitAzureClient) CreateFirstCommitOnHead(ctx context.Context, config *bean2.GitOpsConfigDto) (string, error) { + return impl.CreateReadme(ctx, config) +} + func (impl GitAzureClient) CreateReadme(ctx context.Context, config *bean2.GitOpsConfigDto) (string, error) { var err error @@ -302,7 +306,7 @@ func (impl GitAzureClient) CommitValues(ctx context.Context, config *ChartConfig Project: &impl.project, }) if e := (azuredevops.WrappedError{}); errors.As(err, &e) && e.StatusCode != nil && *e.StatusCode == http2.StatusConflict { - impl.logger.Warn("conflict found in commit azure", "err", err, "config", config) + impl.logger.Warnw("conflict found in commit azure", "config", config, "err", err) if publishStatusConflictError { globalUtil.TriggerGitOpsMetrics("CommitValues", "GitAzureClient", start, err) } diff --git a/pkg/deployment/gitOps/git/GitServiceBitbucket.go b/pkg/deployment/gitOps/git/GitServiceBitbucket.go index 7277dfedb0..bd8a4ace17 100644 --- a/pkg/deployment/gitOps/git/GitServiceBitbucket.go +++ b/pkg/deployment/gitOps/git/GitServiceBitbucket.go @@ -37,12 +37,11 @@ import ( ) const ( - HTTP_URL_PROTOCOL = "http://" - HTTPS_URL_PROTOCOL = "https://" - BITBUCKET_CLONE_BASE_URL = "https://bitbucket.org/" - BITBUCKET_GITOPS_DIR = "bitbucketGitOps" - BITBUCKET_REPO_NOT_FOUND_ERROR = "404 Not Found" - BITBUCKET_COMMIT_TIME_LAYOUT = "2001-01-01T10:00:00+00:00" + HTTP_URL_PROTOCOL = "http://" + HTTPS_URL_PROTOCOL = "https://" + BITBUCKET_CLONE_BASE_URL = "https://bitbucket.org/" + BITBUCKET_GITOPS_DIR = "bitbucketGitOps" + BITBUCKET_COMMIT_TIME_LAYOUT = "2001-01-01T10:00:00+00:00" ) type GitBitbucketClient struct { @@ -199,15 +198,15 @@ func (impl GitBitbucketClient) repoExists(repoOptions *bitbucket.RepositoryOptio }() repo, err := impl.client.Repositories.Repository.Get(repoOptions) - if repo == nil && err.Error() == BITBUCKET_REPO_NOT_FOUND_ERROR { + if repo == nil && strings.Contains(err.Error(), BitbucketRepoNotFoundError.Error()) { return "", false, nil - } - if err != nil { + } else if err != nil { return "", false, err } repoUrl = fmt.Sprintf(BITBUCKET_CLONE_BASE_URL+"%s/%s.git", repoOptions.Owner, repoOptions.RepoSlug) return repoUrl, true, nil } + func (impl GitBitbucketClient) ensureProjectAvailabilityOnHttp(repoOptions *bitbucket.RepositoryOptions) (bool, error) { for count := 0; count < 5; count++ { _, exists, err := impl.repoExists(repoOptions) @@ -231,7 +230,15 @@ func getDir() string { return strconv.FormatInt(r1, 10) } +func (impl GitBitbucketClient) CreateFirstCommitOnHead(ctx context.Context, config *bean2.GitOpsConfigDto) (string, error) { + return impl.createReadme(ctx, config, true) +} + func (impl GitBitbucketClient) CreateReadme(ctx context.Context, config *bean2.GitOpsConfigDto) (string, error) { + return impl.createReadme(ctx, config, false) +} + +func (impl GitBitbucketClient) createReadme(ctx context.Context, config *bean2.GitOpsConfigDto, useDefaultBranch bool) (string, error) { var err error start := time.Now() defer func() { @@ -250,6 +257,8 @@ func (impl GitBitbucketClient) CreateReadme(ctx context.Context, config *bean2.G UserEmailId: config.UserEmailId, } cfg.SetBitBucketBaseDir(getDir()) + // UseDefaultBranch will override the TargetRevision and use the default branch of the repo + cfg.UseDefaultBranch = useDefaultBranch hash, _, err := impl.CommitValues(ctx, cfg, config, true) if err != nil { impl.logger.Errorw("error in creating readme bitbucket", "repo", config.GitRepoName, "err", err) @@ -274,12 +283,15 @@ func (impl GitBitbucketClient) ensureProjectAvailabilityOnSsh(repoOptions *bitbu func (impl GitBitbucketClient) cleanUp(cloneDir string) { err := os.RemoveAll(cloneDir) if err != nil { - impl.logger.Errorw("error cleaning work path for git-ops", "err", err, "cloneDir", cloneDir) + impl.logger.Errorw("error cleaning work path for git-ops", "cloneDir", cloneDir, "err", err) } } func (impl GitBitbucketClient) CommitValues(ctx context.Context, config *ChartConfig, gitOpsConfig *bean2.GitOpsConfigDto, publishStatusConflictError bool) (commitHash string, commitTime time.Time, err error) { + return impl.commitValues(ctx, config, gitOpsConfig, publishStatusConflictError) +} +func (impl GitBitbucketClient) commitValues(ctx context.Context, config *ChartConfig, gitOpsConfig *bean2.GitOpsConfigDto, publishStatusConflictError bool) (commitHash string, commitTime time.Time, err error) { start := time.Now() homeDir, err := os.UserHomeDir() diff --git a/pkg/deployment/gitOps/git/GitServiceGithub.go b/pkg/deployment/gitOps/git/GitServiceGithub.go index 7589b13a02..c5831146ed 100644 --- a/pkg/deployment/gitOps/git/GitServiceGithub.go +++ b/pkg/deployment/gitOps/git/GitServiceGithub.go @@ -78,6 +78,10 @@ func NewGithubClient(host string, token string, org string, logger *zap.SugaredL }, err } +func (impl GitHubClient) getClient() *github.Client { + return impl.client +} + func (impl GitHubClient) DeleteRepository(config *bean2.GitOpsConfigDto) error { var err error start := time.Now() @@ -194,6 +198,10 @@ func (impl GitHubClient) CreateRepository(ctx context.Context, config *bean2.Git return *r.CloneURL, true, isEmpty, detailedErrorGitOpsConfigActions } +func (impl GitHubClient) CreateFirstCommitOnHead(ctx context.Context, config *bean2.GitOpsConfigDto) (string, error) { + return impl.CreateReadme(ctx, config) +} + func (impl GitHubClient) CreateReadme(ctx context.Context, config *bean2.GitOpsConfigDto) (string, error) { var err error start := time.Now() @@ -233,7 +241,7 @@ func (impl GitHubClient) CommitValues(ctx context.Context, config *ChartConfig, if err != nil { responseErr, ok := err.(*github.ErrorResponse) if !ok || responseErr.Response.StatusCode != 404 { - impl.logger.Errorw("error in creating repo github", "err", err, "config", config) + impl.logger.Errorw("error in creating repo github", "config", config, "err", err) globalUtil.TriggerGitOpsMetrics("CommitValues", "GitHubClient", start, err) return "", time.Time{}, err } else { @@ -263,13 +271,13 @@ func (impl GitHubClient) CommitValues(ctx context.Context, config *ChartConfig, } c, httpRes, err := impl.client.Repositories.CreateFile(ctx, impl.org, config.ChartRepoName, path, options) if err != nil && httpRes != nil && httpRes.StatusCode == http2.StatusConflict { - impl.logger.Warn("conflict found in commit github", "err", err, "config", config) + impl.logger.Warnw("conflict found in commit github", "config", config, "err", err) if publishStatusConflictErrorMetrics { globalUtil.TriggerGitOpsMetrics("CommitValues", "GitHubClient", start, err) } return "", time.Time{}, retryFunc.NewRetryableError(err) } else if err != nil { - impl.logger.Errorw("error in commit github", "err", err, "config", config) + impl.logger.Errorw("error in commit github", "config", config, "err", err) globalUtil.TriggerGitOpsMetrics("CommitValues", "GitHubClient", start, err) return "", time.Time{}, err } diff --git a/pkg/deployment/gitOps/git/GitServiceGitlab.go b/pkg/deployment/gitOps/git/GitServiceGitlab.go index 5bbdea47c9..75b1c0a0a8 100644 --- a/pkg/deployment/gitOps/git/GitServiceGitlab.go +++ b/pkg/deployment/gitOps/git/GitServiceGitlab.go @@ -317,6 +317,10 @@ func (impl GitLabClient) GetRepoUrl(config *bean2.GitOpsConfigDto) (repoUrl stri return "", isRepoEmpty, nil } +func (impl GitLabClient) CreateFirstCommitOnHead(ctx context.Context, config *bean2.GitOpsConfigDto) (string, error) { + return impl.CreateReadme(ctx, config) +} + func (impl GitLabClient) CreateReadme(ctx context.Context, config *bean2.GitOpsConfigDto) (string, error) { var err error start := time.Now() @@ -378,7 +382,7 @@ func (impl GitLabClient) CommitValues(ctx context.Context, config *ChartConfig, c, httpRes, err := impl.client.Commits.CreateCommit(fmt.Sprintf("%s/%s", impl.config.GitlabGroupPath, config.ChartRepoName), actions, gitlab.WithContext(ctx)) if err != nil && httpRes != nil && httpRes.StatusCode == http.StatusBadRequest { - impl.logger.Warn("conflict found in commit gitlab", "err", err, "config", config) + impl.logger.Warnw("conflict found in commit gitlab", "config", config, "err", err) if publishStatusConflictError { util.TriggerGitOpsMetrics("CommitValues", "GitLabClient", start, err) } diff --git a/pkg/deployment/gitOps/git/GitService_test.go b/pkg/deployment/gitOps/git/GitService_test.go deleted file mode 100644 index 96da1fbde2..0000000000 --- a/pkg/deployment/gitOps/git/GitService_test.go +++ /dev/null @@ -1,78 +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 git - -import ( - "context" - "github.com/devtron-labs/devtron/api/bean/gitOps" - "github.com/devtron-labs/devtron/internal/util" - git "github.com/devtron-labs/devtron/pkg/deployment/gitOps/git/commandManager" - "testing" -) - -func getTestGithubClient() GitHubClient { - logger, err := util.NewSugardLogger() - gitService := NewGitOpsHelperImpl( - &git.BasicAuth{ - Username: "nishant", - Password: "", - }, logger) - - githubClient, err := NewGithubClient("", "", "test-org", logger, gitService) - if err != nil { - panic(err) - } - return githubClient -} - -func TestGitHubClient_CreateRepository(t *testing.T) { - t.SkipNow() - type args struct { - name string - description string - bitbucketWorkspaceId string - bitbucketProjectKey string - } - tests := []struct { - name string - args args - wantIsNew bool - }{{"test_create", args{ - name: "testn3", - description: "desc2", - bitbucketWorkspaceId: "", - bitbucketProjectKey: "", - }, true}} // TODO: Add test cases. - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - impl := getTestGithubClient() - gitOpsConfigDTO := &gitOps.GitOpsConfigDto{ - Username: tt.args.name, - Description: tt.args.description, - BitBucketWorkspaceId: tt.args.bitbucketWorkspaceId, - BitBucketProjectKey: tt.args.bitbucketProjectKey, - } - _, gotIsNew, _, _ := impl.CreateRepository(context.Background(), gitOpsConfigDTO) - - if gotIsNew != tt.wantIsNew { - t.Errorf("CreateRepository() gotIsNew = %v, want %v", gotIsNew, tt.wantIsNew) - } - - }) - } -} diff --git a/pkg/deployment/gitOps/git/Unimplemented.go b/pkg/deployment/gitOps/git/Unimplemented.go new file mode 100644 index 0000000000..041c112b83 --- /dev/null +++ b/pkg/deployment/gitOps/git/Unimplemented.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 git + +import ( + "context" + "fmt" + "github.com/devtron-labs/devtron/api/bean/gitOps" + "time" +) + +type UnimplementedGitOpsClient struct{} + +func (u *UnimplementedGitOpsClient) CreateRepository(ctx context.Context, config *gitOps.GitOpsConfigDto) (url string, isNew bool, isEmpty bool, detailedErrorGitOpsConfigActions DetailedErrorGitOpsConfigActions) { + return "", false, false, DetailedErrorGitOpsConfigActions{ + StageErrorMap: map[string]error{ + fmt.Sprintf("GitOps will not work"): fmt.Errorf("invalid gitops config found, please configure gitops properly and try again"), + }, + } +} + +func (u *UnimplementedGitOpsClient) CommitValues(ctx context.Context, config *ChartConfig, gitOpsConfig *gitOps.GitOpsConfigDto, publishStatusConflictError bool) (commitHash string, commitTime time.Time, err error) { + return "", time.Time{}, fmt.Errorf("invalid gitops config found, please configure gitops properly and try again") +} + +func (u *UnimplementedGitOpsClient) GetRepoUrl(config *gitOps.GitOpsConfigDto) (repoUrl string, isRepoEmpty bool, err error) { + return "", false, fmt.Errorf("invalid gitops config found, please configure gitops properly and try again") +} + +func (u *UnimplementedGitOpsClient) DeleteRepository(config *gitOps.GitOpsConfigDto) error { + return fmt.Errorf("invalid gitops config found, please configure gitops properly and try again") +} + +func (u *UnimplementedGitOpsClient) CreateReadme(ctx context.Context, config *gitOps.GitOpsConfigDto) (string, error) { + return "", fmt.Errorf("invalid gitops config found, please configure gitops properly and try again") +} + +func (u *UnimplementedGitOpsClient) CreateFirstCommitOnHead(ctx context.Context, config *gitOps.GitOpsConfigDto) (string, error) { + return "", fmt.Errorf("invalid gitops config found, please configure gitops properly and try again") +} diff --git a/pkg/deployment/gitOps/git/commandManager/GitCommandBaseManager.go b/pkg/deployment/gitOps/git/commandManager/GitCommandBaseManager.go index c18586466b..26ecb70abe 100644 --- a/pkg/deployment/gitOps/git/commandManager/GitCommandBaseManager.go +++ b/pkg/deployment/gitOps/git/commandManager/GitCommandBaseManager.go @@ -31,6 +31,11 @@ import ( type GitCommandManagerBase interface { Fetch(ctx GitContext, rootDir string) (response, errMsg string, err error) ListBranch(ctx GitContext, rootDir string) (response, errMsg string, err error) + // GetDefaultBranch returns the default branch of the git repository directory. + // command: git -C rev-parse --abbrev-ref origin/HEAD + // If the repository is empty, it returns an error. + // In that case, use GetCurrentBranch to get the default branch. + GetDefaultBranch(ctx GitContext, rootDir string) (response, errMsg string, err error) PullCli(ctx GitContext, rootDir string, branch string) (response, errMsg string, err error) } @@ -63,7 +68,7 @@ func (impl *GitManagerBaseImpl) ListBranch(ctx GitContext, rootDir string) (resp defer func() { util.TriggerGitOpsMetrics("ListBranch", "GitCli", start, err) }() - impl.logger.Debugw("git branch ", "location", rootDir) + impl.logger.Debugw("git branch -r", "location", rootDir) cmd, cancel := impl.createCmdWithContext(ctx, "git", "-C", rootDir, "branch", "-r") defer cancel() tlsPathInfo, err := git_manager.CreateFilesForTlsData(git_manager.BuildTlsData(ctx.TLSKey, ctx.TLSCertificate, ctx.CACert, ctx.TLSVerificationEnabled), TLS_FOLDER) @@ -73,7 +78,26 @@ func (impl *GitManagerBaseImpl) ListBranch(ctx GitContext, rootDir string) (resp } defer git_manager.DeleteTlsFiles(tlsPathInfo) output, errMsg, err := impl.runCommandWithCred(cmd, ctx.auth, tlsPathInfo) - impl.logger.Debugw("branch output", "root", rootDir, "opt", output, "errMsg", errMsg, "error", err) + impl.logger.Debugw("git branch -r output", "root", rootDir, "opt", output, "errMsg", errMsg, "error", err) + return output, errMsg, err +} + +func (impl *GitManagerBaseImpl) GetDefaultBranch(ctx GitContext, rootDir string) (response, errMsg string, err error) { + start := time.Now() + defer func() { + util.TriggerGitOpsMetrics("GetDefaultBranch", "GitCli", start, err) + }() + impl.logger.Debugw("git rev-parse --abbrev-ref origin/HEAD", "location", rootDir) + cmd, cancel := impl.createCmdWithContext(ctx, "git", "-C", rootDir, "rev-parse", "--abbrev-ref", "origin/HEAD") + defer cancel() + tlsPathInfo, err := git_manager.CreateFilesForTlsData(git_manager.BuildTlsData(ctx.TLSKey, ctx.TLSCertificate, ctx.CACert, ctx.TLSVerificationEnabled), TLS_FOLDER) + if err != nil { + //making it non-blocking + impl.logger.Errorw("error encountered in createFilesForTlsData", "err", err) + } + defer git_manager.DeleteTlsFiles(tlsPathInfo) + output, errMsg, err := impl.runCommandWithCred(cmd, ctx.auth, tlsPathInfo) + impl.logger.Debugw("git rev-parse --abbrev-ref origin/HEAD output", "root", rootDir, "opt", output, "errMsg", errMsg, "error", err) return output, errMsg, err } diff --git a/pkg/deployment/gitOps/git/error.go b/pkg/deployment/gitOps/git/error.go new file mode 100644 index 0000000000..76fd45e152 --- /dev/null +++ b/pkg/deployment/gitOps/git/error.go @@ -0,0 +1,23 @@ +/* + * 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 git + +import ( + "fmt" +) + +var BitbucketRepoNotFoundError = fmt.Errorf("404 Not Found") diff --git a/pkg/deployment/gitOps/git/models.go b/pkg/deployment/gitOps/git/models.go index 19b0b2ac88..5246bf7d45 100644 --- a/pkg/deployment/gitOps/git/models.go +++ b/pkg/deployment/gitOps/git/models.go @@ -29,13 +29,17 @@ type DetailedErrorGitOpsConfigActions struct { } type ChartConfig struct { - ChartName string - ChartLocation string - FileName string //filename - FileContent string - ReleaseMessage string - ChartRepoName string - TargetRevision string + ChartName string + ChartLocation string + FileName string //filename + FileContent string + ReleaseMessage string + ChartRepoName string + TargetRevision string + // UseDefaultBranch will override the TargetRevision and use the default branch of the repo + // This is currently implemented for the bitbucket client only. + // This is used to create the first commit on default branch. + UseDefaultBranch bool UserName string UserEmailId string bitBucketBaseDir string // base directory is required for bitbucket to load the diff --git a/pkg/gitops/GitOpsConfigService.go b/pkg/gitops/GitOpsConfigService.go index f095136674..24a96e375c 100644 --- a/pkg/gitops/GitOpsConfigService.go +++ b/pkg/gitops/GitOpsConfigService.go @@ -128,6 +128,20 @@ func (impl *GitOpsConfigServiceImpl) ValidateAndCreateGitOpsConfig(config *apiBe impl.logger.Errorw("error in getting argo module", "error", err) return apiBean.DetailedErrorGitOpsConfigResponse{}, err } + exists, err := impl.gitOpsRepository.CheckIfGitOpsProviderExist(config.Provider) + if err != nil { + impl.logger.Errorw("error in checking if gitops provider exists", "provider", config.Provider, "err", err) + return apiBean.DetailedErrorGitOpsConfigResponse{}, err + } + if exists { + impl.logger.Errorw("gitops provider already exists", "provider", config.Provider) + err = &util.ApiError{ + HttpStatusCode: http.StatusConflict, + InternalMessage: "gitops provider already exists", + UserMessage: "gitops provider already exists", + } + return apiBean.DetailedErrorGitOpsConfigResponse{}, err + } detailedErrorGitOpsConfigResponse := impl.GitOpsValidateDryRun(argoModule.IsInstalled(), config) if len(detailedErrorGitOpsConfigResponse.StageErrorMap) == 0 { err = impl.updateArgoCdUserDetailIfNotPresent(argoModule) @@ -642,7 +656,7 @@ func (impl *GitOpsConfigServiceImpl) updateGitOpsConfig(request *apiBean.GitOpsC existingModel, err := impl.gitOpsRepository.GetGitOpsConfigActive() if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in creating new gitops config", "error", err) + impl.logger.Errorw("error in getting active gitops config", "error", err) return err } if request.Active { diff --git a/pkg/pipeline/DeploymentPipelineConfigService.go b/pkg/pipeline/DeploymentPipelineConfigService.go index 00bfc63b60..234d79e14a 100644 --- a/pkg/pipeline/DeploymentPipelineConfigService.go +++ b/pkg/pipeline/DeploymentPipelineConfigService.go @@ -30,7 +30,6 @@ import ( helmBean "github.com/devtron-labs/devtron/api/helm-app/service/bean" read4 "github.com/devtron-labs/devtron/api/helm-app/service/read" "github.com/devtron-labs/devtron/client/argocdServer" - bean7 "github.com/devtron-labs/devtron/client/argocdServer/bean" "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/sql/models" "github.com/devtron-labs/devtron/internal/sql/repository" @@ -977,7 +976,7 @@ func (impl *CdPipelineConfigServiceImpl) GetAndValidateArgoApplicationSpec(appli UserMessage: "application with multiple/ empty helm value files are not supported", } } - if strings.ToLower(argoApplicationSpec.Spec.Source.TargetRevision) == bean7.TargetRevisionHead { + if globalUtil.IsHeadTargetRevision(argoApplicationSpec.Spec.Source.TargetRevision) { return argoApplicationSpec, pipelineConfigBean.LinkFailedError{ Reason: pipelineConfigBean.UnsupportedApplicationSpec, UserMessage: "Target revision head not supported", diff --git a/util/DeploymentUtil.go b/util/DeploymentUtil.go index e01ee2b4ee..a415ad4966 100644 --- a/util/DeploymentUtil.go +++ b/util/DeploymentUtil.go @@ -202,3 +202,8 @@ func IsDefaultTargetRevision(branch string) bool { func GetDefaultTargetRevision() string { return argoBean.TargetRevisionMaster } + +// IsHeadTargetRevision checks if the target revision is "HEAD" or "head". +func IsHeadTargetRevision(targetRevision string) bool { + return strings.ToLower(targetRevision) == argoBean.TargetRevisionHead +}