diff --git a/Wire.go b/Wire.go index 8d6b8d5a98..28e21c0a04 100644 --- a/Wire.go +++ b/Wire.go @@ -155,6 +155,8 @@ import ( repository3 "github.com/devtron-labs/devtron/pkg/pipeline/history/repository" repository5 "github.com/devtron-labs/devtron/pkg/pipeline/repository" "github.com/devtron-labs/devtron/pkg/pipeline/types" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus" + repository6 "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/repository" "github.com/devtron-labs/devtron/pkg/plugin" "github.com/devtron-labs/devtron/pkg/policyGovernance" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" @@ -471,6 +473,11 @@ func InitializeApp() (*App, error) { pipeline.NewCiServiceImpl, wire.Bind(new(pipeline.CiService), new(*pipeline.CiServiceImpl)), + workflowStatus.NewWorkflowStageFlowStatusServiceImpl, + wire.Bind(new(workflowStatus.WorkFlowStageStatusService), new(*workflowStatus.WorkFlowStageStatusServiceImpl)), + repository6.NewWorkflowStageRepositoryImpl, + wire.Bind(new(repository6.WorkflowStageRepository), new(*repository6.WorkflowStageRepositoryImpl)), + pipelineConfig.NewCiWorkflowRepositoryImpl, wire.Bind(new(pipelineConfig.CiWorkflowRepository), new(*pipelineConfig.CiWorkflowRepositoryImpl)), diff --git a/api/bean/UserRequest.go b/api/bean/UserRequest.go index 3b56044aaf..bc670469c7 100644 --- a/api/bean/UserRequest.go +++ b/api/bean/UserRequest.go @@ -19,6 +19,7 @@ package bean import ( "encoding/json" "github.com/devtron-labs/devtron/pkg/auth/user/bean" + "github.com/devtron-labs/devtron/pkg/sql" "time" ) @@ -168,3 +169,40 @@ type BulkDeleteRequest struct { type UserRoleGroup struct { RoleGroup *RoleGroup `json:"roleGroup"` } + +type GroupPermissionsAuditDto struct { + RoleGroupInfo *RoleGroup `json:"roleGroupInfo,omitempty"` + EntityAudit sql.AuditLog `json:"entityAudit,omitempty"` +} + +func NewGroupPermissionsAuditDto() *GroupPermissionsAuditDto { + return &GroupPermissionsAuditDto{} +} + +func (pa *GroupPermissionsAuditDto) WithRoleGroupInfo(roleGroupInfo *RoleGroup) *GroupPermissionsAuditDto { + pa.RoleGroupInfo = roleGroupInfo + return pa +} +func (pa *GroupPermissionsAuditDto) WithEntityAudit(entityAudit sql.AuditLog) *GroupPermissionsAuditDto { + pa.EntityAudit = entityAudit + return pa +} + +type UserPermissionsAuditDto struct { + UserInfo *UserInfo `json:"userInfo,omitempty"` + EntityAudit sql.AuditLog `json:"entityAudit,omitempty"` +} + +func NewUserPermissionsAuditDto() *UserPermissionsAuditDto { + return &UserPermissionsAuditDto{} +} + +func (pa *UserPermissionsAuditDto) WithUserInfo(userInfo *UserInfo) *UserPermissionsAuditDto { + pa.UserInfo = userInfo + return pa +} + +func (pa *UserPermissionsAuditDto) WithEntityAudit(entityAudit sql.AuditLog) *UserPermissionsAuditDto { + pa.EntityAudit = entityAudit + return pa +} diff --git a/api/restHandler/app/pipeline/configure/BuildPipelineRestHandler.go b/api/restHandler/app/pipeline/configure/BuildPipelineRestHandler.go index c6321b098c..1a1ec93c2b 100644 --- a/api/restHandler/app/pipeline/configure/BuildPipelineRestHandler.go +++ b/api/restHandler/app/pipeline/configure/BuildPipelineRestHandler.go @@ -25,6 +25,7 @@ import ( "github.com/devtron-labs/devtron/internal/sql/constants" "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging" bean2 "github.com/devtron-labs/devtron/pkg/build/pipeline/bean" + constants2 "github.com/devtron-labs/devtron/pkg/pipeline/constants" "github.com/devtron-labs/devtron/util/stringsUtil" "golang.org/x/exp/maps" "io" @@ -45,7 +46,6 @@ import ( "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin" "github.com/devtron-labs/devtron/pkg/bean" - "github.com/devtron-labs/devtron/pkg/pipeline" bean1 "github.com/devtron-labs/devtron/pkg/pipeline/bean" "github.com/devtron-labs/devtron/pkg/pipeline/types" resourceGroup "github.com/devtron-labs/devtron/pkg/resourceGroup" @@ -663,7 +663,7 @@ func (handler *PipelineConfigRestHandlerImpl) validateCiTriggerRBAC(token string // This is being done for jobs, jobs execute in default-env (devtron-ci) namespace by default. so considering DefaultCiNamespace as env for rbac enforcement envName := "" if triggerEnvironmentId == 0 { - envName = pipeline.DefaultCiWorkflowNamespace + envName = constants2.DefaultCiWorkflowNamespace } appObject := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) workflowObject := handler.enforcerUtil.GetWorkflowRBACByCiPipelineId(ciPipelineId, workflowName) diff --git a/env_gen.json b/env_gen.json index 3217f28913..adec9c458c 100644 --- a/env_gen.json +++ b/env_gen.json @@ -1 +1 @@ -[{"Category":"CD","Fields":[{"Env":"ARGO_APP_MANUAL_SYNC_TIME","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_HELM_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_TIMEOUT_DURATION","EnvType":"string","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS","EnvType":"int","EnvValue":"12","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"6","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CD_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PIPELINE_DEGRADED_TIME","EnvType":"string","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_DEVTRON_APP","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_EXTERNAL_HELM_APP","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_HELM_APP","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"CI_RUNNER","Fields":[{"Env":"AZURE_ACCOUNT_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_ACCOUNT_NAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_CACHE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_LOG","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_CONNECTION_INSECURE","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_URL","EnvType":"string","EnvValue":"http://devtron-minio.devtroncd:9000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BASE_LOG_LOCATION_PATH","EnvType":"string","EnvValue":"/home/devtron/","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_GCP_CREDENTIALS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_PROVIDER","EnvType":"","EnvValue":"S3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ACCESS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_BUCKET_VERSIONED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT_INSECURE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_SECRET_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/devtron/buildx","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_K8S_DRIVER_OPTIONS","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_PROVENANCE_MODE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILD_LOG_TTL_VALUE_IN_SECS","EnvType":"int","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CACHE_LIMIT","EnvType":"int64","EnvValue":"5000000000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"cd-runner","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_IGNORE_DOCKER_CACHE","EnvType":"bool","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_RUNNER_DOCKER_MTU_VALUE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_SUCCESS_AUTO_TRIGGER_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_VOLUME_MOUNTS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"arsenal-v1/ci-artifacts","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_BUCKET","EnvType":"string","EnvValue":"devtron-pro-ci-logs","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"arsenal-v1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET","EnvType":"string","EnvValue":"ci-caching","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_LOGS_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_NAMESPACE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CI_IMAGE","EnvType":"string","EnvValue":"686244538589.dkr.ecr.us-east-2.amazonaws.com/cirunner:47","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtron-ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TARGET_PLATFORM","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DOCKER_BUILD_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/docker","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_BUILD_CONTEXT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_CM_NAME","EnvType":"string","EnvValue":"blob-storage-cm","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_SECRET_NAME","EnvType":"string","EnvValue":"blob-storage-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_API_SECRET","EnvType":"string","EnvValue":"devtroncd-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_PAYLOAD","EnvType":"string","EnvValue":"{\"ciProjectDetails\":[{\"gitRepository\":\"https://github.com/vikram1601/getting-started-nodejs.git\",\"checkoutPath\":\"./abc\",\"commitHash\":\"239077135f8cdeeccb7857e2851348f558cb53d3\",\"commitTime\":\"2022-10-30T20:00:00\",\"branch\":\"master\",\"message\":\"Update README.md\",\"author\":\"User Name \"}],\"dockerImage\":\"445808685819.dkr.ecr.us-east-2.amazonaws.com/orch:23907713-2\"}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_WEB_HOOK_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IGNORE_CM_CS_IN_CI_JOB","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_COUNT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_INTERVAL","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCANNER_ENDPOINT","EnvType":"string","EnvValue":"http://image-scanner-new-demo-devtroncd-service.devtroncd:80","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_MAX_RETRIES","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IN_APP_LOGGING_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_CD_WORKFLOW_RUNNER_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_CI_WORKFLOW_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODE","EnvType":"string","EnvValue":"DEV","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_SERVER_HOST","EnvType":"string","EnvValue":"localhost:4222","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_HOST","EnvType":"string","EnvValue":"http://devtroncd-orchestrator-service-prod.devtroncd/webhook/msg/nats","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PRE_CI_CACHE_PATH","EnvType":"string","EnvValue":"/devtroncd-cache","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOW_DOCKER_BUILD_ARGS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SKIP_CI_JOB_BUILD_CACHE_PUSH_PULL","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SKIP_CREATING_ECR_REPO","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINATION_GRACE_PERIOD_SECS","EnvType":"int","EnvValue":"180","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_QUERY_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CI_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BUILDX","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_DOCKER_API_TO_GET_DIGEST","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_EXTERNAL_NODE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WF_CONTROLLER_INSTANCE_ID","EnvType":"string","EnvValue":"devtron-runner","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_CACHE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"ci-runner","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"DEVTRON","Fields":[{"Env":"-","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_IMAGE","EnvType":"string","EnvValue":"quay.io/devtron/chart-sync:1227622d-132-3775","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_JOB_RESOURCES_OBJ","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_AUTO_SYNC_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_COUNT","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_DELAY","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ASYNC_BUILDX_CACHE_EXPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_MODE_MIN","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PORT","EnvType":"string","EnvValue":"8000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CExpirationTime","EnvType":"int","EnvValue":"600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_TRIGGER_CRON_TIME","EnvType":"int","EnvValue":"2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_STATUS_UPDATE_CRON","EnvType":"string","EnvValue":"*/5 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CLI_CMD_TIMEOUT_GLOBAL_SECONDS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CLUSTER_STATUS_CRON_TIME","EnvType":"int","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CONSUMER_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_LOG_TIME_LIMIT","EnvType":"int64","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TIMEOUT","EnvType":"float64","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_BOM_URL","EnvType":"string","EnvValue":"https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEX_SECRET_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_CHART_NAME","EnvType":"string","EnvValue":"devtron-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_URL","EnvType":"string","EnvValue":"https://helm.devtron.ai","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLATION_TYPE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_MODULES_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_SECRET_NAME","EnvType":"string","EnvValue":"devtron-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_VERSION_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.release","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CID","EnvType":"string","EnvValue":"example-app","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CLIENT_ID","EnvType":"string","EnvValue":"argo-cd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CSTOREKEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_JWTKEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_RURL","EnvType":"string","EnvValue":"http://127.0.0.1:8080/callback","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_SECRET","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ECR_REPO_NAME_PREFIX","EnvType":"string","EnvValue":"test/","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EPHEMERAL_SERVER_VERSION_REGEX","EnvType":"string","EnvValue":"v[1-9]\\.\\b(2[3-9]\\|[3-9][0-9])\\b.*","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EVENT_URL","EnvType":"string","EnvValue":"http://localhost:3000/notify","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXECUTE_WIRE_NIL_CHECKER","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CI_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FORCE_SECURITY_SCANNING","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_REPO_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GO_RUNTIME_ENV","EnvType":"string","EnvValue":"production","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_ORG_ID","EnvType":"int","EnvValue":"2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PASSWORD","EnvType":"string","EnvValue":"prom-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PORT","EnvType":"string","EnvValue":"8090","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HIDE_IMAGE_TAGGING_HARD_DELETE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IGNORE_AUTOCOMPLETE_AUTH_CHECK","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_GROUP_NAME","EnvType":"string","EnvValue":"installer.devtron.ai","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_RESOURCE","EnvType":"string","EnvValue":"installers","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_VERSION","EnvType":"string","EnvValue":"v1alpha1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IS_INTERNAL_USE","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"JwtExpirationTime","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_CLIENT_MAX_IDLE_CONNS_PER_HOST","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_IDLE_CONN_TIMEOUT","EnvType":"int","EnvValue":"300","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_KEEPALIVE","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_TIMEOUT","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TLS_HANDSHAKE_TIMEOUT","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_RECEIVE_MSG_SIZE","EnvType":"int","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_SEND_MSG_SIZE","EnvType":"int","EnvValue":"4","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_URL","EnvType":"string","EnvValue":"http://lens-milandevtron-service:80","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOGGER_DEV_MODE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_SESSION_PER_USER","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODULE_METADATA_API_URL","EnvType":"string","EnvValue":"https://api.devtron.ai/module?name=%s","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODULE_STATUS_HANDLING_CRON_DURATION_MIN","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_ACK_WAIT_IN_SECS","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_BUFFER_SIZE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_MAX_AGE","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_PROCESSING_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_REPLICAS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NOTIFICATION_MEDIUM","EnvType":"NotificationMedium","EnvValue":"rest","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"OTEL_COLLECTOR_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_EXPORT_PROM_METRICS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_FAILURE_QUERIES","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_QUERY","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_SLOW_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_QUERY_DUR_THRESHOLD","EnvType":"int64","EnvValue":"5000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PLUGIN_NAME","EnvType":"string","EnvValue":"Pull images from container repository","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROPAGATE_EXTRA_LABELS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROXY_SERVICE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESTRICT_TERMINAL_ACCESS_FOR_NON_SUPER_USER","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUNTIME_CONFIG_LOCAL_DEV","EnvType":"LocalDevMode","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_FORMAT","EnvType":"string","EnvValue":"@{{%s}}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_HANDLE_PRIMITIVES","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_NAME_REGEX","EnvType":"string","EnvValue":"^[a-zA-Z][a-zA-Z0-9_-]{0,62}[a-zA-Z0-9]$","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOULD_CHECK_NAMESPACE_ON_CLONE","EnvType":"bool","EnvValue":"false","EnvDescription":"should we check if namespace exists or not while cloning app","Example":"","Deprecated":"false"},{"Env":"SOCKET_DISCONNECT_DELAY_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SOCKET_HEARTBEAT_SECONDS","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"STREAM_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SYSTEM_VAR_PREFIX","EnvType":"string","EnvValue":"DEVTRON_","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"default","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_INACTIVE_DURATION_IN_MINS","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_STATUS_SYNC_In_SECS","EnvType":"int","EnvValue":"600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_LOG_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PASSWORD","EnvType":"string","EnvValue":"postgrespw","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PORT","EnvType":"string","EnvValue":"55000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_FOR_FAILED_CI_BUILD","EnvType":"string","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_IN_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USER_SESSION_DURATION_SECONDS","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_API_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_CUSTOM_HTTP_TRANSPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_GIT_CLI","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_RBAC_CREATION_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"VARIABLE_CACHE_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"VARIABLE_EXPRESSION_REGEX","EnvType":"string","EnvValue":"@{{([^}]+)}}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WEBHOOK_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"GITOPS","Fields":[{"Env":"ACD_CM","EnvType":"string","EnvValue":"argocd-cm","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_PASSWORD","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_SECRET_NAME","EnvType":"string","EnvValue":"devtron-gitops-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS","EnvType":"string","EnvValue":"Deployment,Rollout,StatefulSet,ReplicaSet","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS_BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"INFRA_SETUP","Fields":[{"Env":"DASHBOARD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_PORT","EnvType":"string","EnvValue":"3000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_HOST","EnvType":"string","EnvValue":"http://localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_PORT","EnvType":"string","EnvValue":"5556","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_PROTOCOL","EnvType":"string","EnvValue":"REST","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_URL","EnvType":"string","EnvValue":"127.0.0.1:7070","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HELM_CLIENT_URL","EnvType":"string","EnvValue":"127.0.0.1:50051","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"POSTGRES","Fields":[{"Env":"APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"Application name","Example":"","Deprecated":"false"},{"Env":"CASBIN_DATABASE","EnvType":"string","EnvValue":"casbin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"address of postgres service","Example":"postgresql-postgresql.devtroncd","Deprecated":"false"},{"Env":"PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"postgres database to be made connection with","Example":"orchestrator, casbin, git_sensor, lens","Deprecated":"false"},{"Env":"PG_PASSWORD","EnvType":"string","EnvValue":"{password}","EnvDescription":"password for postgres, associated with PG_USER","Example":"confidential ;)","Deprecated":"false"},{"Env":"PG_PORT","EnvType":"string","EnvValue":"5432","EnvDescription":"port of postgresql service","Example":"5432","Deprecated":"false"},{"Env":"PG_READ_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"user for postgres","Example":"postgres","Deprecated":"false"},{"Env":"PG_WRITE_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"RBAC","Fields":[{"Env":"ENFORCER_CACHE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENFORCER_CACHE_EXPIRATION_IN_SEC","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENFORCER_MAX_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_CASBIN_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"}]}] \ No newline at end of file +[{"Category":"CD","Fields":[{"Env":"ARGO_APP_MANUAL_SYNC_TIME","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_HELM_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_CRON_TIME","EnvType":"string","EnvValue":"*/2 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PIPELINE_STATUS_TIMEOUT_DURATION","EnvType":"string","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEPLOY_STATUS_CRON_GET_PIPELINE_DEPLOYED_WITHIN_HOURS","EnvType":"int","EnvValue":"12","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_ARGO_CD_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_CHART_INSTALL_REQUEST_TIMEOUT","EnvType":"int","EnvValue":"6","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CD_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HELM_PIPELINE_STATUS_CHECK_ELIGIBLE_TIME","EnvType":"string","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PIPELINE_DEGRADED_TIME","EnvType":"string","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_DEVTRON_APP","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_EXTERNAL_HELM_APP","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REVISION_HISTORY_LIMIT_HELM_APP","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"CI_RUNNER","Fields":[{"Env":"AZURE_ACCOUNT_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_ACCOUNT_NAME","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_CACHE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_BLOB_CONTAINER_CI_LOG","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_CONNECTION_INSECURE","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"AZURE_GATEWAY_URL","EnvType":"string","EnvValue":"http://devtron-minio.devtroncd:9000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BASE_LOG_LOCATION_PATH","EnvType":"string","EnvValue":"/home/devtron/","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_GCP_CREDENTIALS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_PROVIDER","EnvType":"","EnvValue":"S3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ACCESS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_BUCKET_VERSIONED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_ENDPOINT_INSECURE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_S3_SECRET_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/devtron/buildx","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_K8S_DRIVER_OPTIONS","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_PROVENANCE_MODE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILD_LOG_TTL_VALUE_IN_SECS","EnvType":"int","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CACHE_LIMIT","EnvType":"int64","EnvValue":"5000000000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"cd-runner","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_BASE_CIDR","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_DEFAULT_ADDRESS_POOL_SIZE","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_IGNORE_DOCKER_CACHE","EnvType":"bool","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_RUNNER_DOCKER_MTU_VALUE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_SUCCESS_AUTO_TRIGGER_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_VOLUME_MOUNTS_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_EXECUTOR_TYPE","EnvType":"","EnvValue":"AWF","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"arsenal-v1/ci-artifacts","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_BUCKET","EnvType":"string","EnvValue":"devtron-pro-ci-logs","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_BUILD_LOGS_KEY_PREFIX","EnvType":"string","EnvValue":"arsenal-v1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET","EnvType":"string","EnvValue":"ci-caching","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CACHE_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_ARTIFACT_KEY_LOCATION","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_LOGS_BUCKET_REGION","EnvType":"string","EnvValue":"us-east-2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_NAMESPACE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CD_TIMEOUT","EnvType":"int64","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_CI_IMAGE","EnvType":"string","EnvValue":"686244538589.dkr.ecr.us-east-2.amazonaws.com/cirunner:47","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtron-ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TARGET_PLATFORM","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DOCKER_BUILD_CACHE_PATH","EnvType":"string","EnvValue":"/var/lib/docker","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_BUILD_CONTEXT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"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":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_BLOB_STORAGE_SECRET_NAME","EnvType":"string","EnvValue":"blob-storage-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_LABEL_SELECTOR","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_KEY","EnvType":"string","EnvValue":"dedicated","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CD_NODE_TAINTS_VALUE","EnvType":"string","EnvValue":"ci","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_API_SECRET","EnvType":"string","EnvValue":"devtroncd-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_PAYLOAD","EnvType":"string","EnvValue":"{\"ciProjectDetails\":[{\"gitRepository\":\"https://github.com/vikram1601/getting-started-nodejs.git\",\"checkoutPath\":\"./abc\",\"commitHash\":\"239077135f8cdeeccb7857e2851348f558cb53d3\",\"commitTime\":\"2022-10-30T20:00:00\",\"branch\":\"master\",\"message\":\"Update README.md\",\"author\":\"User Name \"}],\"dockerImage\":\"445808685819.dkr.ecr.us-east-2.amazonaws.com/orch:23907713-2\"}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXTERNAL_CI_WEB_HOOK_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IGNORE_CM_CS_IN_CI_JOB","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_COUNT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_RETRY_INTERVAL","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCANNER_ENDPOINT","EnvType":"string","EnvValue":"http://image-scanner-new-demo-devtroncd-service.devtroncd:80","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_MAX_RETRIES","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IMAGE_SCAN_RETRY_DELAY","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IN_APP_LOGGING_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_CD_WORKFLOW_RUNNER_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_CI_WORKFLOW_RETRIES","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODE","EnvType":"string","EnvValue":"DEV","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_SERVER_HOST","EnvType":"string","EnvValue":"localhost:4222","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_HOST","EnvType":"string","EnvValue":"http://devtroncd-orchestrator-service-prod.devtroncd/webhook/msg/nats","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ORCH_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PRE_CI_CACHE_PATH","EnvType":"string","EnvValue":"/devtroncd-cache","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOW_DOCKER_BUILD_ARGS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SKIP_CI_JOB_BUILD_CACHE_PUSH_PULL","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SKIP_CREATING_ECR_REPO","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINATION_GRACE_PERIOD_SECS","EnvType":"int","EnvValue":"180","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_QUERY_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CD_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BLOB_STORAGE_CONFIG_IN_CI_WORKFLOW","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_BUILDX","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_DOCKER_API_TO_GET_DIGEST","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_EXTERNAL_NODE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WF_CONTROLLER_INSTANCE_ID","EnvType":"string","EnvValue":"devtron-runner","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_CACHE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WORKFLOW_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"ci-runner","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"DEVTRON","Fields":[{"Env":"-","EnvType":"","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_IMAGE","EnvType":"string","EnvValue":"quay.io/devtron/chart-sync:1227622d-132-3775","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_JOB_RESOURCES_OBJ","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"APP_SYNC_SERVICE_ACCOUNT","EnvType":"string","EnvValue":"chart-sync","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_AUTO_SYNC_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_COUNT_ON_CONFLICT","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_GIT_COMMIT_RETRY_DELAY_ON_CONFLICT","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_COUNT","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ARGO_REPO_REGISTER_RETRY_DELAY","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ASYNC_BUILDX_CACHE_EXPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BLOB_STORAGE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"BUILDX_CACHE_MODE_MIN","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CD_PORT","EnvType":"string","EnvValue":"8000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CExpirationTime","EnvType":"int","EnvValue":"600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_TRIGGER_CRON_TIME","EnvType":"int","EnvValue":"2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CI_WORKFLOW_STATUS_UPDATE_CRON","EnvType":"string","EnvValue":"*/5 * * * *","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CLI_CMD_TIMEOUT_GLOBAL_SECONDS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CLUSTER_STATUS_CRON_TIME","EnvType":"int","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"CONSUMER_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_LOG_TIME_LIMIT","EnvType":"int64","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEFAULT_TIMEOUT","EnvType":"float64","EnvValue":"3600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_BOM_URL","EnvType":"string","EnvValue":"https://raw.githubusercontent.com/devtron-labs/devtron/%s/charts/devtron/devtron-bom.yaml","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_DEX_SECRET_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_CHART_NAME","EnvType":"string","EnvValue":"devtron-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_RELEASE_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_NAME","EnvType":"string","EnvValue":"devtron","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_HELM_REPO_URL","EnvType":"string","EnvValue":"https://helm.devtron.ai","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_INSTALLATION_TYPE","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_MODULES_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.modules","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_SECRET_NAME","EnvType":"string","EnvValue":"devtron-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEVTRON_VERSION_IDENTIFIER_IN_HELM_VALUES","EnvType":"string","EnvValue":"installer.release","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CID","EnvType":"string","EnvValue":"example-app","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CLIENT_ID","EnvType":"string","EnvValue":"argo-cd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_CSTOREKEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_JWTKEY","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_RURL","EnvType":"string","EnvValue":"http://127.0.0.1:8080/callback","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_SECRET","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ECR_REPO_NAME_PREFIX","EnvType":"string","EnvValue":"test/","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_ARGO_CD_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENABLE_ASYNC_INSTALL_DEVTRON_CHART","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EPHEMERAL_SERVER_VERSION_REGEX","EnvType":"string","EnvValue":"v[1-9]\\.\\b(2[3-9]\\|[3-9][0-9])\\b.*","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EVENT_URL","EnvType":"string","EnvValue":"http://localhost:3000/notify","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXECUTE_WIRE_NIL_CHECKER","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"EXPOSE_CI_METRICS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FEATURE_RESTART_WORKLOAD_WORKER_POOL_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"FORCE_SECURITY_SCANNING","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_REPO_PREFIX","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GO_RUNTIME_ENV","EnvType":"string","EnvValue":"production","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_ORG_ID","EnvType":"int","EnvValue":"2","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PASSWORD","EnvType":"string","EnvValue":"prom-operator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_PORT","EnvType":"string","EnvValue":"8090","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GRAFANA_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HIDE_IMAGE_TAGGING_HARD_DELETE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IGNORE_AUTOCOMPLETE_AUTH_CHECK","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_GROUP_NAME","EnvType":"string","EnvValue":"installer.devtron.ai","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_RESOURCE","EnvType":"string","EnvValue":"installers","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"INSTALLER_CRD_OBJECT_VERSION","EnvType":"string","EnvValue":"v1alpha1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"IS_INTERNAL_USE","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"JwtExpirationTime","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_CLIENT_MAX_IDLE_CONNS_PER_HOST","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_IDLE_CONN_TIMEOUT","EnvType":"int","EnvValue":"300","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_KEEPALIVE","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TCP_TIMEOUT","EnvType":"int","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"K8s_TLS_HANDSHAKE_TIMEOUT","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_RECEIVE_MSG_SIZE","EnvType":"int","EnvValue":"20","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"KUBELINK_GRPC_MAX_SEND_MSG_SIZE","EnvType":"int","EnvValue":"4","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LENS_URL","EnvType":"string","EnvValue":"http://lens-milandevtron-service:80","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LIMIT_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOGGER_DEV_MODE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"LOG_LEVEL","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MAX_SESSION_PER_USER","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODULE_METADATA_API_URL","EnvType":"string","EnvValue":"https://api.devtron.ai/module?name=%s","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"MODULE_STATUS_HANDLING_CRON_DURATION_MIN","EnvType":"int","EnvValue":"3","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_ACK_WAIT_IN_SECS","EnvType":"int","EnvValue":"120","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_BUFFER_SIZE","EnvType":"int","EnvValue":"-1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_MAX_AGE","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_PROCESSING_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NATS_MSG_REPLICAS","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"NOTIFICATION_MEDIUM","EnvType":"NotificationMedium","EnvValue":"rest","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"OTEL_COLLECTOR_URL","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PARALLELISM_LIMIT_FOR_TAG_PROCESSING","EnvType":"int","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_EXPORT_PROM_METRICS","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_FAILURE_QUERIES","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_ALL_QUERY","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_LOG_SLOW_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_QUERY_DUR_THRESHOLD","EnvType":"int64","EnvValue":"5000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PLUGIN_NAME","EnvType":"string","EnvValue":"Pull images from container repository","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROPAGATE_EXTRA_LABELS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PROXY_SERVICE_CONFIG","EnvType":"string","EnvValue":"{}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_CPU","EnvType":"string","EnvValue":"0.5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"REQ_CI_MEM","EnvType":"string","EnvValue":"3G","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESTRICT_TERMINAL_ACCESS_FOR_NON_SUPER_USER","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUNTIME_CONFIG_LOCAL_DEV","EnvType":"LocalDevMode","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RUN_HELM_INSTALL_IN_ASYNC_MODE_HELM_APPS","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_ENABLED","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_FORMAT","EnvType":"string","EnvValue":"@{{%s}}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_HANDLE_PRIMITIVES","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SCOPED_VARIABLE_NAME_REGEX","EnvType":"string","EnvValue":"^[a-zA-Z][a-zA-Z0-9_-]{0,62}[a-zA-Z0-9]$","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SHOULD_CHECK_NAMESPACE_ON_CLONE","EnvType":"bool","EnvValue":"false","EnvDescription":"should we check if namespace exists or not while cloning app","Example":"","Deprecated":"false"},{"Env":"SOCKET_DISCONNECT_DELAY_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SOCKET_HEARTBEAT_SECONDS","EnvType":"int","EnvValue":"25","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"STREAM_CONFIG_JSON","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"SYSTEM_VAR_PREFIX","EnvType":"string","EnvValue":"DEVTRON_","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_DEFAULT_NAMESPACE","EnvType":"string","EnvValue":"default","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_INACTIVE_DURATION_IN_MINS","EnvType":"int","EnvValue":"10","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TERMINAL_POD_STATUS_SYNC_In_SECS","EnvType":"int","EnvValue":"600","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_LOG_QUERY","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PASSWORD","EnvType":"string","EnvValue":"postgrespw","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_PORT","EnvType":"string","EnvValue":"55000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TEST_PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_FOR_FAILED_CI_BUILD","EnvType":"string","EnvValue":"15","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"TIMEOUT_IN_SECONDS","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USER_SESSION_DURATION_SECONDS","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_ARTIFACT_LISTING_API_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_CUSTOM_HTTP_TRANSPORT","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_DEPLOYMENT_CONFIG_DATA","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_GIT_CLI","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_RBAC_CREATION_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"VARIABLE_CACHE_ENABLED","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"VARIABLE_EXPRESSION_REGEX","EnvType":"string","EnvValue":"@{{([^}]+)}}","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"WEBHOOK_TOKEN","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"GITOPS","Fields":[{"Env":"ACD_CM","EnvType":"string","EnvValue":"argocd-cm","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_PASSWORD","EnvType":"string","EnvValue":"","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ACD_USERNAME","EnvType":"string","EnvValue":"admin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GITOPS_SECRET_NAME","EnvType":"string","EnvValue":"devtron-gitops-secret","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS","EnvType":"string","EnvValue":"Deployment,Rollout,StatefulSet,ReplicaSet","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"RESOURCE_LIST_FOR_REPLICAS_BATCH_SIZE","EnvType":"int","EnvValue":"5","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"INFRA_SETUP","Fields":[{"Env":"DASHBOARD_HOST","EnvType":"string","EnvValue":"localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_NAMESPACE","EnvType":"string","EnvValue":"devtroncd","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DASHBOARD_PORT","EnvType":"string","EnvValue":"3000","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_HOST","EnvType":"string","EnvValue":"http://localhost","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"DEX_PORT","EnvType":"string","EnvValue":"5556","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_PROTOCOL","EnvType":"string","EnvValue":"REST","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_TIMEOUT","EnvType":"int","EnvValue":"0","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"GIT_SENSOR_URL","EnvType":"string","EnvValue":"127.0.0.1:7070","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"HELM_CLIENT_URL","EnvType":"string","EnvValue":"127.0.0.1:50051","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"POSTGRES","Fields":[{"Env":"APP","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"Application name","Example":"","Deprecated":"false"},{"Env":"CASBIN_DATABASE","EnvType":"string","EnvValue":"casbin","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_ADDR","EnvType":"string","EnvValue":"127.0.0.1","EnvDescription":"address of postgres service","Example":"postgresql-postgresql.devtroncd","Deprecated":"false"},{"Env":"PG_DATABASE","EnvType":"string","EnvValue":"orchestrator","EnvDescription":"postgres database to be made connection with","Example":"orchestrator, casbin, git_sensor, lens","Deprecated":"false"},{"Env":"PG_PASSWORD","EnvType":"string","EnvValue":"{password}","EnvDescription":"password for postgres, associated with PG_USER","Example":"confidential ;)","Deprecated":"false"},{"Env":"PG_PORT","EnvType":"string","EnvValue":"5432","EnvDescription":"port of postgresql service","Example":"5432","Deprecated":"false"},{"Env":"PG_READ_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"PG_USER","EnvType":"string","EnvValue":"postgres","EnvDescription":"user for postgres","Example":"postgres","Deprecated":"false"},{"Env":"PG_WRITE_TIMEOUT","EnvType":"int64","EnvValue":"30","EnvDescription":"","Example":"","Deprecated":"false"}]},{"Category":"RBAC","Fields":[{"Env":"ENFORCER_CACHE","EnvType":"bool","EnvValue":"false","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENFORCER_CACHE_EXPIRATION_IN_SEC","EnvType":"int","EnvValue":"86400","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"ENFORCER_MAX_BATCH_SIZE","EnvType":"int","EnvValue":"1","EnvDescription":"","Example":"","Deprecated":"false"},{"Env":"USE_CASBIN_V2","EnvType":"bool","EnvValue":"true","EnvDescription":"","Example":"","Deprecated":"false"}]}] \ No newline at end of file diff --git a/env_gen.md b/env_gen.md index 99d49b535d..8e7461ef9b 100644 --- a/env_gen.md +++ b/env_gen.md @@ -76,6 +76,7 @@ | DEFAULT_TARGET_PLATFORM | string | | | | false | | DOCKER_BUILD_CACHE_PATH | string |/var/lib/docker | | | false | | ENABLE_BUILD_CONTEXT | bool |false | | | false | + | ENABLE_WORKFLOW_EXECUTION_STAGE | bool |true | if enabled then we will display build stages separately for CI/Job/Pre-Post CD | true | false | | EXTERNAL_BLOB_STORAGE_CM_NAME | string |blob-storage-cm | | | false | | EXTERNAL_BLOB_STORAGE_SECRET_NAME | string |blob-storage-secret | | | false | | EXTERNAL_CD_NODE_LABEL_SELECTOR | | | | | false | diff --git a/go.mod b/go.mod index 86d9506f99..4088841309 100644 --- a/go.mod +++ b/go.mod @@ -288,8 +288,8 @@ require gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect replace ( github.com/argoproj/argo-workflows/v3 v3.5.10 => github.com/devtron-labs/argo-workflows/v3 v3.5.13 - github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2 - github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2 + github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250213074742-042aeadc9d72 + github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250213074742-042aeadc9d72 github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.5.5 k8s.io/api => k8s.io/api v0.29.7 diff --git a/go.sum b/go.sum index 50156b584f..98b244a9af 100644 --- a/go.sum +++ b/go.sum @@ -792,10 +792,10 @@ github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzq github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/devtron-labs/argo-workflows/v3 v3.5.13 h1:3pINq0gXOSeTw2z/vYe+j80lRpSN5Rp/8mfQORh8SmU= github.com/devtron-labs/argo-workflows/v3 v3.5.13/go.mod h1:/vqxcovDPT4zqr4DjR5v7CF8ggpY1l3TSa2CIG3jmjA= -github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2 h1:8QjRav7pCDb32Pz8HwbS1P8QQJ1QSDb3wJgAmNYkNeU= -github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2/go.mod h1:5lv4Wfj5ERhhvDGXe2IeES6qxjvUVCcohaRwKnWBMNo= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2 h1:8VByFEk14t2z2DDaD/7pTgwSM7zFYEMqfthLWpt2M3w= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2/go.mod h1:1QJJLpgJSkb5Jm9xPeKAk+kXb0QgBOOOgJj0cgYhAVA= +github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250213074742-042aeadc9d72 h1:BEFuaGkJgvu+8H+To2sMJQusaD3PZwQbxn0ikIpkWbE= +github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250213074742-042aeadc9d72/go.mod h1:5lv4Wfj5ERhhvDGXe2IeES6qxjvUVCcohaRwKnWBMNo= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250213074742-042aeadc9d72 h1:hPVJuggt+zZjcf3PFaXy7ZrBV7VPB8+ztMVUErmHX3Y= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250213074742-042aeadc9d72/go.mod h1:1QJJLpgJSkb5Jm9xPeKAk+kXb0QgBOOOgJj0cgYhAVA= github.com/devtron-labs/go-bitbucket v0.9.60-beta h1:VEx1jvDgdtDPS6A1uUFoaEi0l1/oLhbr+90xOwr6sDU= github.com/devtron-labs/go-bitbucket v0.9.60-beta/go.mod h1:GnuiCesvh8xyHeMCb+twm8lBR/kQzJYSKL28ZfObp1Y= github.com/devtron-labs/protos v0.0.3-0.20240802105333-92ee9bb85d80 h1:xwbTeijNTf4/j1v+tSfwVqwLVnReas/NqEKeQHvSTys= diff --git a/internal/sql/repository/AppListingRepository.go b/internal/sql/repository/AppListingRepository.go index 864f87921e..f8456932b2 100644 --- a/internal/sql/repository/AppListingRepository.go +++ b/internal/sql/repository/AppListingRepository.go @@ -308,10 +308,10 @@ func (impl AppListingRepositoryImpl) FetchAppsByEnvironmentV2(appListingFilter h // if any pipeline found get the latest deployment time if len(pipelineIds) > 0 { - query := impl.appListingRepositoryQueryBuilder.BuildAppListingQueryLastDeploymentTimeV2(pipelineIds) + query, queryParams := impl.appListingRepositoryQueryBuilder.BuildAppListingQueryLastDeploymentTimeV2(pipelineIds) impl.Logger.Debugw("basic app detail query: ", query) start := time.Now() - _, err := impl.dbConnection.Query(&lastDeployedTimeDTO, query) + _, err := impl.dbConnection.Query(&lastDeployedTimeDTO, query, queryParams...) middleware.AppListingDuration.WithLabelValues("buildAppListingQueryLastDeploymentTime", "devtron").Observe(time.Since(start).Seconds()) if err != nil { impl.Logger.Errorw("error in getting latest deployment time for given pipelines", "err", err, "pipelines", pipelineIds, "query", query) diff --git a/internal/sql/repository/CiArtifactRepository.go b/internal/sql/repository/CiArtifactRepository.go index 2f3c41ae37..4f765c8eee 100644 --- a/internal/sql/repository/CiArtifactRepository.go +++ b/internal/sql/repository/CiArtifactRepository.go @@ -362,8 +362,8 @@ func (impl CiArtifactRepositoryImpl) GetArtifactsByCDPipelineV3(listingFilterOpt artifactsResp := make([]*CiArtifactWithExtraData, 0, listingFilterOpts.Limit) var artifacts []*CiArtifact totalCount := 0 - finalQuery := BuildQueryForParentTypeCIOrWebhook(*listingFilterOpts) - _, err := impl.dbConnection.Query(&artifactsResp, finalQuery) + finalQuery, finalQueryParams := BuildQueryForParentTypeCIOrWebhook(*listingFilterOpts) + _, err := impl.dbConnection.Query(&artifactsResp, finalQuery, finalQueryParams...) if err != nil { return nil, totalCount, err } diff --git a/internal/sql/repository/CiArtifactsListingQueryBuilder.go b/internal/sql/repository/CiArtifactsListingQueryBuilder.go index f262fc3732..e13ea4632d 100644 --- a/internal/sql/repository/CiArtifactsListingQueryBuilder.go +++ b/internal/sql/repository/CiArtifactsListingQueryBuilder.go @@ -20,24 +20,28 @@ import ( "fmt" "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/internal/sql/repository/helper" + "github.com/go-pg/pg" ) const EmptyLikeRegex = "%%" -func BuildQueryForParentTypeCIOrWebhook(listingFilterOpts bean.ArtifactsListFilterOptions) string { - commonPaginatedQueryPart := fmt.Sprintf(" cia.image LIKE '%v'", listingFilterOpts.SearchString) +func BuildQueryForParentTypeCIOrWebhook(listingFilterOpts bean.ArtifactsListFilterOptions) (string, []interface{}) { + commonPaginatedQueryPart, commonPaginatedQueryParams := " cia.image LIKE ?", []interface{}{listingFilterOpts.SearchString} orderByClause := " ORDER BY cia.id DESC" - limitOffsetQueryPart := fmt.Sprintf(" LIMIT %v OFFSET %v", listingFilterOpts.Limit, listingFilterOpts.Offset) + limitOffsetQueryPart, limitOffsetQueryParams := fmt.Sprintf(" LIMIT ? OFFSET ?"), []interface{}{listingFilterOpts.Limit, listingFilterOpts.Offset} finalQuery := "" + var finalQueryParams []interface{} + var remainingQueryParams []interface{} if listingFilterOpts.ParentStageType == bean.CI_WORKFLOW_TYPE { selectQuery := " SELECT cia.* " remainingQuery := " FROM ci_artifact cia" + " INNER JOIN ci_pipeline cp ON (cp.id=cia.pipeline_id or (cp.id=cia.component_id and cia.data_source='post_ci' ) )" + - " INNER JOIN pipeline p ON (p.ci_pipeline_id = cp.id and p.id=%v )" + + " INNER JOIN pipeline p ON (p.ci_pipeline_id = cp.id and p.id=? )" + " WHERE " - remainingQuery = fmt.Sprintf(remainingQuery, listingFilterOpts.PipelineId) + remainingQueryParams = []interface{}{listingFilterOpts.PipelineId} if len(listingFilterOpts.ExcludeArtifactIds) > 0 { - remainingQuery += fmt.Sprintf("cia.id NOT IN (%s) AND ", helper.GetCommaSepratedString(listingFilterOpts.ExcludeArtifactIds)) + remainingQuery += "cia.id NOT IN (?) AND " + remainingQueryParams = append(remainingQueryParams, pg.In(listingFilterOpts.ExcludeArtifactIds)) } countQuery := " SELECT count(cia.id) as total_count" @@ -47,19 +51,24 @@ func BuildQueryForParentTypeCIOrWebhook(listingFilterOpts bean.ArtifactsListFilt } else if listingFilterOpts.ParentStageType == bean.WEBHOOK_WORKFLOW_TYPE { selectQuery := " SELECT cia.* " remainingQuery := " FROM ci_artifact cia " + - " WHERE cia.external_ci_pipeline_id = %v AND " - remainingQuery = fmt.Sprintf(remainingQuery, listingFilterOpts.ParentId) + " WHERE cia.external_ci_pipeline_id = ? AND " + remainingQueryParams = []interface{}{listingFilterOpts.ParentId} if len(listingFilterOpts.ExcludeArtifactIds) > 0 { - remainingQuery += fmt.Sprintf("cia.id NOT IN (%s) AND ", helper.GetCommaSepratedString(listingFilterOpts.ExcludeArtifactIds)) + remainingQuery += "cia.id NOT IN (?) AND " + remainingQueryParams = append(remainingQueryParams, pg.In(listingFilterOpts.ExcludeArtifactIds)) } countQuery := " SELECT count(cia.id) as total_count" totalCountQuery := countQuery + remainingQuery + commonPaginatedQueryPart selectQuery = fmt.Sprintf("%s,(%s) ", selectQuery, totalCountQuery) finalQuery = selectQuery + remainingQuery + commonPaginatedQueryPart + orderByClause + limitOffsetQueryPart - } - return finalQuery + finalQueryParams = append(finalQueryParams, remainingQueryParams...) + finalQueryParams = append(finalQueryParams, commonPaginatedQueryParams...) + finalQueryParams = append(finalQueryParams, remainingQueryParams...) + finalQueryParams = append(finalQueryParams, commonPaginatedQueryParams...) + finalQueryParams = append(finalQueryParams, limitOffsetQueryParams...) + return finalQuery, finalQueryParams } func BuildQueryForArtifactsForCdStage(listingFilterOptions bean.ArtifactsListFilterOptions) string { diff --git a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go index ae7d013696..b527185e19 100644 --- a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go +++ b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go @@ -160,15 +160,17 @@ func (impl AppListingRepositoryQueryBuilder) TestForCommonAppFilter(appListingFi return query, queryParams } -func (impl AppListingRepositoryQueryBuilder) BuildAppListingQueryLastDeploymentTimeV2(pipelineIDs []int) string { +func (impl AppListingRepositoryQueryBuilder) BuildAppListingQueryLastDeploymentTimeV2(pipelineIDs []int) (string, []interface{}) { whereCondition := "" + queryParams := []interface{}{} if len(pipelineIDs) > 0 { - whereCondition += fmt.Sprintf(" Where pco.pipeline_id IN (%s) ", GetCommaSepratedString(pipelineIDs)) + whereCondition += " Where pco.pipeline_id IN (?) " + queryParams = append(queryParams, pg.In(pipelineIDs)) } query := "select pco.pipeline_id , MAX(pco.created_on) as last_deployed_time" + " from pipeline_config_override pco" + whereCondition + " GROUP BY pco.pipeline_id;" - return query + return query, queryParams } func (impl AppListingRepositoryQueryBuilder) GetAppIdsQueryWithPaginationForLastDeployedSearch(appListingFilter AppListingFilter) (string, []interface{}) { diff --git a/internal/sql/repository/pipelineConfig/CdWorfkflowRepository.go b/internal/sql/repository/pipelineConfig/CdWorfkflowRepository.go index 906dd3d326..a737a7076a 100644 --- a/internal/sql/repository/pipelineConfig/CdWorfkflowRepository.go +++ b/internal/sql/repository/pipelineConfig/CdWorfkflowRepository.go @@ -19,7 +19,6 @@ package pipelineConfig import ( "context" "errors" - "fmt" apiBean "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/client/gitSensor" "github.com/devtron-labs/devtron/internal/sql/repository" @@ -41,8 +40,8 @@ type CdWorkflowRepository interface { FindCdWorkflowMetaByEnvironmentId(appId int, environmentId int, offset int, size int) ([]CdWorkflowRunner, error) FindCdWorkflowMetaByPipelineId(pipelineId int, offset int, size int) ([]CdWorkflowRunner, error) FindArtifactByPipelineIdAndRunnerType(pipelineId int, runnerType apiBean.WorkflowType, limit int, runnerStatuses []string) ([]CdWorkflowRunner, error) - SaveWorkFlowRunner(wfr *CdWorkflowRunner) (*CdWorkflowRunner, error) - UpdateWorkFlowRunner(wfr *CdWorkflowRunner) error + SaveWorkFlowRunnerWithTx(wfr *CdWorkflowRunner, tx *pg.Tx) (*CdWorkflowRunner, error) + UpdateWorkFlowRunnerWithTx(wfr *CdWorkflowRunner, tx *pg.Tx) error UpdateIsArtifactUploaded(wfrId int, isArtifactUploaded workflow.ArtifactUploadedType) error GetPreviousQueuedRunners(cdWfrId, pipelineId int) ([]*CdWorkflowRunner, error) UpdateRunnerStatusToFailedForIds(errMsg string, triggeredBy int32, cdWfrIds ...int) error @@ -452,14 +451,14 @@ func (impl *CdWorkflowRepositoryImpl) FindLastPreOrPostTriggeredByEnvironmentId( return wfr, err } -func (impl *CdWorkflowRepositoryImpl) SaveWorkFlowRunner(wfr *CdWorkflowRunner) (*CdWorkflowRunner, error) { - err := impl.dbConnection.Insert(wfr) +func (impl *CdWorkflowRepositoryImpl) SaveWorkFlowRunnerWithTx(wfr *CdWorkflowRunner, tx *pg.Tx) (*CdWorkflowRunner, error) { + err := tx.Insert(wfr) return wfr, err } -func (impl *CdWorkflowRepositoryImpl) UpdateWorkFlowRunner(wfr *CdWorkflowRunner) error { +func (impl *CdWorkflowRepositoryImpl) UpdateWorkFlowRunnerWithTx(wfr *CdWorkflowRunner, tx *pg.Tx) error { wfr.Message = util.GetTruncatedMessage(wfr.Message, 1000) - err := impl.dbConnection.Update(wfr) + err := tx.Update(wfr) return err } @@ -539,10 +538,9 @@ func (impl *CdWorkflowRepositoryImpl) FindBasicWorkflowRunnerById(wfrId int) (*C func (impl *CdWorkflowRepositoryImpl) FindRetriedWorkflowCountByReferenceId(wfrId int) (int, error) { retryCount := 0 - query := fmt.Sprintf("select count(id) "+ - "from cd_workflow_runner where ref_cd_workflow_runner_id = %v", wfrId) + query := "select count(id) from cd_workflow_runner where ref_cd_workflow_runner_id = ?" - _, err := impl.dbConnection.Query(&retryCount, query) + _, err := impl.dbConnection.Query(&retryCount, query, wfrId) return retryCount, err } diff --git a/internal/sql/repository/pipelineConfig/CiWorkflowRepository.go b/internal/sql/repository/pipelineConfig/CiWorkflowRepository.go index f313bfe06b..f472a6b06c 100644 --- a/internal/sql/repository/pipelineConfig/CiWorkflowRepository.go +++ b/internal/sql/repository/pipelineConfig/CiWorkflowRepository.go @@ -17,9 +17,7 @@ package pipelineConfig import ( - "fmt" "github.com/devtron-labs/devtron/internal/sql/constants" - "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" "github.com/go-pg/pg" @@ -28,9 +26,9 @@ import ( ) type CiWorkflowRepository interface { - SaveWorkFlow(wf *CiWorkflow) error + SaveWorkFlowWithTx(wf *CiWorkflow, tx *pg.Tx) error FindLastTriggeredWorkflow(pipelineId int) (*CiWorkflow, error) - UpdateWorkFlow(wf *CiWorkflow) error + UpdateWorkFlowWithTx(wf *CiWorkflow, tx *pg.Tx) error UpdateArtifactUploaded(id int, isUploaded workflow.ArtifactUploadedType) error FindByStatusesIn(activeStatuses []string) ([]*CiWorkflow, error) FindByPipelineId(pipelineId int, offset int, size int) ([]WorkflowWithArtifact, error) @@ -236,10 +234,9 @@ func (impl *CiWorkflowRepositoryImpl) FindById(id int) (*CiWorkflow, error) { func (impl *CiWorkflowRepositoryImpl) FindRetriedWorkflowCountByReferenceId(id int) (int, error) { retryCount := 0 - query := fmt.Sprintf("select count(*) "+ - "from ci_workflow where ref_ci_workflow_id = %v", id) + query := "select count(*) from ci_workflow where ref_ci_workflow_id = ?" - _, err := impl.dbConnection.Query(&retryCount, query) + _, err := impl.dbConnection.Query(&retryCount, query, id) return retryCount, err } @@ -266,13 +263,13 @@ func (impl *CiWorkflowRepositoryImpl) FindCiWorkflowGitTriggersByIds(ids []int) return workflows, err } -func (impl *CiWorkflowRepositoryImpl) SaveWorkFlow(wf *CiWorkflow) error { - err := impl.dbConnection.Insert(wf) +func (impl *CiWorkflowRepositoryImpl) SaveWorkFlowWithTx(wf *CiWorkflow, tx *pg.Tx) error { + err := tx.Insert(wf) return err } -func (impl *CiWorkflowRepositoryImpl) UpdateWorkFlow(wf *CiWorkflow) error { - err := impl.dbConnection.Update(wf) +func (impl *CiWorkflowRepositoryImpl) UpdateWorkFlowWithTx(wf *CiWorkflow, tx *pg.Tx) error { + err := tx.Update(wf) return err } @@ -339,9 +336,8 @@ func (impl *CiWorkflowRepositoryImpl) FindLastTriggeredWorkflowGitTriggersByArti } query := "SELECT cw.git_triggers,cw.id,cw.triggered_by,cw.ci_pipeline_id,cia.id as ci_artifact_id" + " FROM ci_workflow cw INNER JOIN ci_artifact cia on cia.ci_workflow_id = cw.id " + - " WHERE cia.id IN (%s)" - query = fmt.Sprintf(query, helper.GetCommaSepratedString(ciArtifactIds)) - _, err := impl.dbConnection.Query(&workflows, query) + " WHERE cia.id IN (?)" + _, err := impl.dbConnection.Query(&workflows, query, pg.In(ciArtifactIds)) return workflows, err } diff --git a/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow/CdWorkflowBean.go b/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow/CdWorkflowBean.go index 2568ea98ae..911c4c048e 100644 --- a/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow/CdWorkflowBean.go +++ b/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow/CdWorkflowBean.go @@ -6,7 +6,7 @@ import ( "github.com/devtron-labs/devtron/client/argocdServer/bean" ) -var WfrTerminalStatusList = []string{WorkflowAborted, WorkflowFailed, WorkflowSucceeded, bean.HIBERNATING, string(health.HealthStatusHealthy), string(health.HealthStatusDegraded)} +var WfrTerminalStatusList = []string{WorkflowAborted, WorkflowFailed, WorkflowSucceeded, bean.HIBERNATING, string(health.HealthStatusHealthy), string(health.HealthStatusDegraded), WorkflowTimedOut, WorkflowCancel} type WorkflowStatus int @@ -34,6 +34,7 @@ const ( WorkflowTypeDeploy = "DEPLOY" WorkflowTypePre = "PRE" WorkflowTypePost = "POST" + WorkflowWaitingToStart = "WaitingToStart" ) func (a WorkflowStatus) String() string { @@ -60,3 +61,6 @@ type CdWorkflowRunnerArtifactMetadata struct { ParentCiArtifact int `pg:"parent_ci_artifact"` Scanned bool `pg:"scanned"` } + +const WorkflowCancel = "CANCELLED" +const POD_DELETED_MESSAGE = "pod deleted" diff --git a/internal/util/adapter.go b/internal/util/adapter.go new file mode 100644 index 0000000000..2a2a3a0f62 --- /dev/null +++ b/internal/util/adapter.go @@ -0,0 +1,10 @@ +package util + +func GetApiErrorAdapter(httpStatusCode int, code, userMessage, internalMessage string) *ApiError { + return &ApiError{ + HttpStatusCode: httpStatusCode, + Code: code, + UserMessage: userMessage, + InternalMessage: internalMessage, + } +} diff --git a/pkg/app/AppService.go b/pkg/app/AppService.go index 541db8cc37..077688bb16 100644 --- a/pkg/app/AppService.go +++ b/pkg/app/AppService.go @@ -38,6 +38,7 @@ import ( bean6 "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/bean" "github.com/devtron-labs/devtron/pkg/deployment/manifest/deploymentTemplate/read" bean4 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/bean" + "github.com/devtron-labs/devtron/pkg/workflow/cd" "io/ioutil" "net/url" "path" @@ -125,6 +126,7 @@ type AppServiceImpl struct { appListingService AppListingService deploymentConfigService common2.DeploymentConfigService envConfigOverrideReadService read.EnvConfigOverrideService + cdWorkflowRunnerService cd.CdWorkflowRunnerService } type AppService interface { @@ -164,7 +166,8 @@ func NewAppService( deploymentTemplateService deploymentTemplate.DeploymentTemplateService, appListingService AppListingService, deploymentConfigService common2.DeploymentConfigService, - envConfigOverrideReadService read.EnvConfigOverrideService) *AppServiceImpl { + envConfigOverrideReadService read.EnvConfigOverrideService, + cdWorkflowRunnerService cd.CdWorkflowRunnerService) *AppServiceImpl { appServiceImpl := &AppServiceImpl{ mergeUtil: mergeUtil, pipelineOverrideRepository: pipelineOverrideRepository, @@ -194,6 +197,7 @@ func NewAppService( appListingService: appListingService, deploymentConfigService: deploymentConfigService, envConfigOverrideReadService: envConfigOverrideReadService, + cdWorkflowRunnerService: cdWorkflowRunnerService, } return appServiceImpl } @@ -1005,7 +1009,7 @@ func (impl *AppServiceImpl) UpdateCdWorkflowRunnerByACDObject(app *v1alpha1.Appl } wfr.UpdatedBy = 1 wfr.UpdatedOn = time.Now() - err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(wfr) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(wfr) if err != nil { impl.logger.Errorw("error on update cd workflow runner", "wfr", wfr, "app", app, "err", err) return err diff --git a/pkg/auth/user/RoleGroupService.go b/pkg/auth/user/RoleGroupService.go index 664521276d..d0d4c71f73 100644 --- a/pkg/auth/user/RoleGroupService.go +++ b/pkg/auth/user/RoleGroupService.go @@ -89,11 +89,15 @@ func (impl RoleGroupServiceImpl) CreateRoleGroup(request *bean.RoleGroup) (*bean defer tx.Rollback() if request.Id > 0 { - _, err := impl.roleGroupRepository.GetRoleGroupById(request.Id) + roleGroup, err := impl.roleGroupRepository.GetRoleGroupById(request.Id) if err != nil { impl.logger.Errorw("error while fetching user from db", "error", err) return nil, err } + if roleGroup != nil && len(roleGroup.Name) > 0 { + return nil, util.GetApiErrorAdapter(400, "400", "role group already exist with the given id", "role group already exist with the given id") + } + return nil, util.GetApiErrorAdapter(400, "400", "id not supported in create request", "id not supported in create request") } else { //loading policy for safety casbin2.LoadPolicy() diff --git a/pkg/auth/user/repository/UserRepository.go b/pkg/auth/user/repository/UserRepository.go index 99274d9221..b5c3cc625b 100644 --- a/pkg/auth/user/repository/UserRepository.go +++ b/pkg/auth/user/repository/UserRepository.go @@ -181,9 +181,10 @@ func (impl UserRepositoryImpl) GetAllExecutingQuery(query string, queryParams [] func (impl UserRepositoryImpl) FetchActiveUserByEmail(email string) (bean.UserInfo, error) { var users bean.UserInfo + emailSearchQuery, queryParams := helper.GetEmailSearchQuery("u", email) query := fmt.Sprintf("SELECT u.id, u.email_id, u.access_token, u.user_type FROM users u"+ - " WHERE u.active = true and %s order by u.updated_on desc", helper.GetEmailSearchQuery("u", email)) - _, err := impl.dbConnection.Query(&users, query, email) + " WHERE u.active = true and %s order by u.updated_on desc", emailSearchQuery) + _, err := impl.dbConnection.Query(&users, query, queryParams...) if err != nil { impl.Logger.Errorw("Exception caught:", "err", err) return users, err @@ -197,12 +198,13 @@ func (impl UserRepositoryImpl) FetchUserDetailByEmail(email string) (bean.UserIn var users []bean.UserRole var userFinal bean.UserInfo + emailSearchQuery, queryParams := helper.GetEmailSearchQuery("u", email) query := fmt.Sprintf("SELECT u.id, u.email_id, u.user_type, r.role FROM users u"+ " INNER JOIN user_roles ur ON ur.user_id=u.id"+ " INNER JOIN roles r ON r.id=ur.role_id"+ " WHERE %s and u.active = true"+ - " ORDER BY u.updated_on desc;", helper.GetEmailSearchQuery("u", email)) - _, err := impl.dbConnection.Query(&users, query, email) + " ORDER BY u.updated_on desc;", emailSearchQuery) + _, err := impl.dbConnection.Query(&users, query, queryParams...) if err != nil { return userFinal, err } diff --git a/pkg/auth/user/repository/helper/UserRepositoryQueryBuilder.go b/pkg/auth/user/repository/helper/UserRepositoryQueryBuilder.go index 9dbf55d439..976bbfcd6b 100644 --- a/pkg/auth/user/repository/helper/UserRepositoryQueryBuilder.go +++ b/pkg/auth/user/repository/helper/UserRepositoryQueryBuilder.go @@ -84,9 +84,11 @@ func GetQueryForGroupListingWithFilters(req *bean.ListingRequest) (string, []int orderCondition := "" if len(req.SortBy) > 0 && !req.CountCheck { - orderCondition += fmt.Sprintf(" order by %s ", req.SortBy) + orderCondition += " order by " if req.SortOrder == bean2.Desc { - orderCondition += fmt.Sprintf(" %s ", bean2.Desc) + orderCondition += fmt.Sprintf(" %s %s ", req.SortBy, bean2.Desc) + } else { + orderCondition += fmt.Sprintf(" %s ", req.SortBy) } } if req.Size > 0 && !req.CountCheck && !req.ShowAll { @@ -103,9 +105,10 @@ func GetQueryForGroupListingWithFilters(req *bean.ListingRequest) (string, []int } -func GetEmailSearchQuery(usersTableAlias string, emailId string) string { +func GetEmailSearchQuery(usersTableAlias string, emailId string) (string, []interface{}) { + queryParams := []interface{}{emailId, emailId} expression := fmt.Sprintf( - "( (%s.user_type is NULL and %s.email_id ILIKE '%s' ) or (%s.user_type='apiToken' and %s.email_id='%s') )", - usersTableAlias, usersTableAlias, emailId, usersTableAlias, usersTableAlias, emailId) - return expression + "( (%s.user_type is NULL and %s.email_id ILIKE ? ) or (%s.user_type='apiToken' and %s.email_id=?) )", + usersTableAlias, usersTableAlias, usersTableAlias, usersTableAlias) + return expression, queryParams } diff --git a/pkg/deployment/trigger/devtronApps/PostStageTriggerService.go b/pkg/deployment/trigger/devtronApps/PostStageTriggerService.go index b22609e0a8..8a11b06a6b 100644 --- a/pkg/deployment/trigger/devtronApps/PostStageTriggerService.go +++ b/pkg/deployment/trigger/devtronApps/PostStageTriggerService.go @@ -119,7 +119,7 @@ func (impl *TriggerServiceImpl) TriggerPostStage(request bean.TriggerRequest) (* runner.Status = cdWorkflow.WorkflowFailed runner.Message = err.Error() runner.FinishedOn = time.Now() - _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) + _ = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(runner) return nil, err } @@ -129,7 +129,7 @@ func (impl *TriggerServiceImpl) TriggerPostStage(request bean.TriggerRequest) (* runner.Status = cdWorkflow.WorkflowFailed runner.Message = err.Error() runner.FinishedOn = time.Now() - _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) + _ = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(runner) return nil, err } manifestPushTempate, err := impl.getManifestPushTemplateForPostStage(request, envDevploymentConfig, jobHelmPackagePath, cdStageWorkflowRequest, cdWf, runner, pipeline, triggeredBy, triggeredAt) @@ -143,7 +143,7 @@ func (impl *TriggerServiceImpl) TriggerPostStage(request bean.TriggerRequest) (* return nil, err } wfr.ImagePathReservationIds = pluginImagePathReservationIds - err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(&wfr) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(&wfr) if err != nil { impl.logger.Error("error in updating image path reservation ids in cd workflow runner", "err", "err") } diff --git a/pkg/deployment/trigger/devtronApps/PreStageTriggerService.go b/pkg/deployment/trigger/devtronApps/PreStageTriggerService.go index 913bd9663d..6e0b81c207 100644 --- a/pkg/deployment/trigger/devtronApps/PreStageTriggerService.go +++ b/pkg/deployment/trigger/devtronApps/PreStageTriggerService.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" blob_storage "github.com/devtron-labs/common-lib/blob-storage" commonBean "github.com/devtron-labs/common-lib/workflow" bean2 "github.com/devtron-labs/devtron/api/bean" @@ -135,11 +136,11 @@ func (impl *TriggerServiceImpl) TriggerPreStage(request bean.TriggerRequest) (*b runner.Status = cdWorkflow.WorkflowFailed runner.Message = err.Error() runner.FinishedOn = time.Now() - _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) + _ = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(runner) return nil, err } else { runner.ImagePathReservationIds = imagePathReservationIds - _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) + _ = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(runner) } _, span = otel.Tracer("orchestrator").Start(ctx, "cdWorkflowService.SubmitWorkflow") @@ -152,7 +153,7 @@ func (impl *TriggerServiceImpl) TriggerPreStage(request bean.TriggerRequest) (*b runner.Status = cdWorkflow.WorkflowFailed runner.Message = err.Error() runner.FinishedOn = time.Now() - _ = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) + _ = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(runner) return nil, err } manifestPushTemplate, err := impl.getManifestPushTemplateForPreStage(ctx, envDeploymentConfig, pipeline, artifact, jobHelmPackagePath, cdWf, runner, triggeredBy, triggeredAt, request) @@ -251,6 +252,7 @@ func (impl *TriggerServiceImpl) createStartingWfAndRunner(request bean.TriggerRe WorkflowType: request.WorkflowType, ExecutorType: impl.config.GetWorkflowExecutorType(), Status: cdWorkflow.WorkflowStarting, // starting PreStage + PodStatus: string(v1alpha1.NodePending), TriggeredBy: triggeredBy, StartedOn: triggeredAt, Namespace: request.RunStageInEnvNamespace, @@ -262,7 +264,7 @@ func (impl *TriggerServiceImpl) createStartingWfAndRunner(request bean.TriggerRe ReferenceId: request.TriggerContext.ReferenceId, } _, span := otel.Tracer("orchestrator").Start(ctx, "cdWorkflowRepository.SaveWorkFlowRunner") - _, err = impl.cdWorkflowRepository.SaveWorkFlowRunner(runner) + _, err = impl.cdWorkflowRunnerService.SaveCDWorkflowRunnerWithStage(runner) span.End() if err != nil { return nil, nil, err @@ -311,7 +313,7 @@ func (impl *TriggerServiceImpl) checkVulnerabilityStatusAndFailWfIfNeeded(ctx co runner.FinishedOn = time.Now() runner.UpdatedOn = time.Now() runner.UpdatedBy = triggeredBy - err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(runner) if err != nil { impl.logger.Errorw("error in updating wfr status due to vulnerable image", "err", err) return err diff --git a/pkg/deployment/trigger/devtronApps/TriggerService.go b/pkg/deployment/trigger/devtronApps/TriggerService.go index faf30adb53..ca847d06e8 100644 --- a/pkg/deployment/trigger/devtronApps/TriggerService.go +++ b/pkg/deployment/trigger/devtronApps/TriggerService.go @@ -172,6 +172,7 @@ type TriggerServiceImpl struct { gitOperationService git.GitOperationService attributeService attributes.AttributesService clusterRepository repository5.ClusterRepository + cdWorkflowRunnerService cd.CdWorkflowRunnerService } func NewTriggerServiceImpl(logger *zap.SugaredLogger, @@ -230,6 +231,7 @@ func NewTriggerServiceImpl(logger *zap.SugaredLogger, gitOperationService git.GitOperationService, attributeService attributes.AttributesService, clusterRepository repository5.ClusterRepository, + cdWorkflowRunnerService cd.CdWorkflowRunnerService, ) (*TriggerServiceImpl, error) { impl := &TriggerServiceImpl{ logger: logger, @@ -292,6 +294,7 @@ func NewTriggerServiceImpl(logger *zap.SugaredLogger, ciCdPipelineOrchestrator: ciCdPipelineOrchestrator, gitOperationService: gitOperationService, attributeService: attributeService, + cdWorkflowRunnerService: cdWorkflowRunnerService, clusterRepository: clusterRepository, } @@ -518,7 +521,7 @@ func (impl *TriggerServiceImpl) ManualCdTrigger(triggerContext bean.TriggerConte AuditLog: sql.AuditLog{CreatedOn: triggeredAt, CreatedBy: overrideRequest.UserId, UpdatedOn: triggeredAt, UpdatedBy: overrideRequest.UserId}, ReferenceId: triggerContext.ReferenceId, } - savedWfr, err := impl.cdWorkflowRepository.SaveWorkFlowRunner(runner) + savedWfr, err := impl.cdWorkflowRunnerService.SaveCDWorkflowRunnerWithStage(runner) if err != nil { impl.logger.Errorw("err in creating cdWorkflowRunner, ManualCdTrigger", "cdWorkflowId", cdWorkflowId, "err", err) return 0, "", nil, err @@ -649,7 +652,7 @@ func (impl *TriggerServiceImpl) TriggerAutomaticDeployment(request bean.TriggerR AuditLog: sql.AuditLog{CreatedOn: triggeredAt, CreatedBy: triggeredBy, UpdatedOn: triggeredAt, UpdatedBy: triggeredBy}, ReferenceId: request.TriggerContext.ReferenceId, } - savedWfr, err := impl.cdWorkflowRepository.SaveWorkFlowRunner(runner) + savedWfr, err := impl.cdWorkflowRunnerService.SaveCDWorkflowRunnerWithStage(runner) if err != nil { return err } diff --git a/pkg/eventProcessor/in/WorkflowEventProcessorService.go b/pkg/eventProcessor/in/WorkflowEventProcessorService.go index e6b696136e..d91bd56caf 100644 --- a/pkg/eventProcessor/in/WorkflowEventProcessorService.go +++ b/pkg/eventProcessor/in/WorkflowEventProcessorService.go @@ -438,51 +438,55 @@ func (impl *WorkflowEventProcessorImpl) SubscribeCDWorkflowStatusUpdate() error return } - wfrId, wfrStatus, err := impl.cdHandler.UpdateWorkflow(wfStatus) + wfrId, wfrStatus, stateChanged, err := impl.cdHandler.UpdateWorkflow(wfStatus) impl.logger.Debugw("UpdateWorkflow", "wfrId", wfrId, "wfrStatus", wfrStatus) if err != nil { impl.logger.Error("err", err) return } - wfr, err := impl.cdWorkflowRepository.FindWorkflowRunnerById(wfrId) - if err != nil { - impl.logger.Errorw("could not get wf runner", "err", err) - return - } - if wfrStatus == string(v1alpha1.NodeFailed) || wfrStatus == string(v1alpha1.NodeError) { - if len(wfr.ImagePathReservationIds) > 0 { - err := impl.cdHandler.DeactivateImageReservationPathsOnFailure(wfr.ImagePathReservationIds) - if err != nil { - impl.logger.Errorw("error in removing image path reservation ") - } - } - } - if wfrStatus == string(v1alpha1.NodeSucceeded) || wfrStatus == string(v1alpha1.NodeFailed) || wfrStatus == string(v1alpha1.NodeError) { - eventType := eventUtil.EventType(0) - if wfrStatus == string(v1alpha1.NodeSucceeded) { - eventType = eventUtil.Success - } else if wfrStatus == string(v1alpha1.NodeFailed) || wfrStatus == string(v1alpha1.NodeError) { - eventType = eventUtil.Fail + if stateChanged { + wfr, err := impl.cdWorkflowRepository.FindWorkflowRunnerById(wfrId) + if err != nil { + impl.logger.Errorw("could not get wf runner", "wfrId", wfrId, "err", err) + return } - if wfr != nil && executors.CheckIfReTriggerRequired(wfrStatus, wfStatus.Message, wfr.Status) { - err = impl.workflowDagExecutor.HandleCdStageReTrigger(wfr) - if err != nil { - //check if this log required or not - impl.logger.Errorw("error in HandleCdStageReTrigger", "error", err) + if wfrStatus == string(v1alpha1.NodeFailed) || wfrStatus == string(v1alpha1.NodeError) { + if len(wfr.ImagePathReservationIds) > 0 { + err := impl.cdHandler.DeactivateImageReservationPathsOnFailure(wfr.ImagePathReservationIds) + if err != nil { + impl.logger.Errorw("error in removing image path reservation ", "imagePathReservationIds", wfr.ImagePathReservationIds, "err", err) + } } } - if wfr.WorkflowType == apiBean.CD_WORKFLOW_TYPE_PRE || wfr.WorkflowType == apiBean.CD_WORKFLOW_TYPE_POST { - event, _ := impl.eventFactory.Build(eventType, &wfr.CdWorkflow.PipelineId, wfr.CdWorkflow.Pipeline.AppId, &wfr.CdWorkflow.Pipeline.EnvironmentId, eventUtil.CD) - impl.logger.Debugw("event pre stage", "event", event) - event = impl.eventFactory.BuildExtraCDData(event, wfr, 0, wfr.WorkflowType) - _, evtErr := impl.eventClient.WriteNotificationEvent(event) - if evtErr != nil { - impl.logger.Errorw("CD stage post fail or success event unable to sent", "error", evtErr) + wfStatusInEvent := string(wfStatus.Phase) + if wfStatusInEvent == string(v1alpha1.NodeSucceeded) || wfStatusInEvent == string(v1alpha1.NodeFailed) || wfStatusInEvent == string(v1alpha1.NodeError) { + // the re-trigger should only happen when we get a pod deleted event. + if wfr != nil && executors.CheckIfReTriggerRequired(wfrStatus, wfStatus.Message, wfr.Status) { + err = impl.workflowDagExecutor.HandleCdStageReTrigger(wfr) + if err != nil { + // check if this log required or not + impl.logger.Errorw("error in HandleCdStageReTrigger", "workflowRunnerId", wfr.Id, "workflowStatus", wfrStatus, "workflowStatusMessage", wfStatus.Message, "error", err) + } + impl.logger.Debugw("re-triggered cd stage", "workflowRunnerId", wfr.Id, "workflowStatus", wfrStatus, "workflowStatusMessage", wfStatus.Message) + } else { + // we send this notification on *workflow_runner* status, both success and failure + // during workflow runner failure, particularly when failure occurred due to pod deletion , we get two events from kubewatch. + // event1: with failure status + exit-code [need to send notification] + // event2: with failure status + pod deletion message [skip notification] + eventType := eventUtil.EventType(0) + if wfStatusInEvent == string(v1alpha1.NodeSucceeded) { + eventType = eventUtil.Success + } else if wfStatusInEvent == string(v1alpha1.NodeFailed) || wfStatusInEvent == string(v1alpha1.NodeError) { + eventType = eventUtil.Fail + } + impl.sendPrePostCdNotificationEvent(eventType, wfr) } } + } else { + impl.logger.Debugw("no state change detected for the cd workflow status update, ignoring this event", "workflowRunnerId", wfrId, "wfrStatus", wfrStatus) } } @@ -505,6 +509,18 @@ func (impl *WorkflowEventProcessorImpl) SubscribeCDWorkflowStatusUpdate() error return nil } +func (impl *WorkflowEventProcessorImpl) sendPrePostCdNotificationEvent(eventType eventUtil.EventType, wfr *pipelineConfig.CdWorkflowRunner) { + if wfr.WorkflowType == apiBean.CD_WORKFLOW_TYPE_PRE || wfr.WorkflowType == apiBean.CD_WORKFLOW_TYPE_POST { + event, _ := impl.eventFactory.Build(eventType, &wfr.CdWorkflow.PipelineId, wfr.CdWorkflow.Pipeline.AppId, &wfr.CdWorkflow.Pipeline.EnvironmentId, eventUtil.CD) + impl.logger.Debugw("event pre stage", "event", event) + event = impl.eventFactory.BuildExtraCDData(event, wfr, 0, wfr.WorkflowType) + _, evtErr := impl.eventClient.WriteNotificationEvent(event) + if evtErr != nil { + impl.logger.Errorw("CD stage post fail or success event unable to sent", "error", evtErr) + } + } +} + func (impl *WorkflowEventProcessorImpl) extractCiCompleteEventFrom(msg *model.PubSubMsg) (bean.CiCompleteEvent, error) { ciCompleteEvent := bean.CiCompleteEvent{} err := json.Unmarshal([]byte(msg.Data), &ciCompleteEvent) diff --git a/pkg/notifier/NotificationConfigService.go b/pkg/notifier/NotificationConfigService.go index 02b97660f4..00681337eb 100644 --- a/pkg/notifier/NotificationConfigService.go +++ b/pkg/notifier/NotificationConfigService.go @@ -294,23 +294,14 @@ func (impl *NotificationConfigServiceImpl) BuildNotificationSettingsResponse(not if config.Providers != nil && len(config.Providers) > 0 { var slackIds []*int var webhookIds []*int - var sesUserIds []int32 - var smtpUserIds []int32 var providerConfigs []*beans.ProvidersConfig for _, item := range config.Providers { - // if item.ConfigId > 0 that means, user is of user repository, else user email is custom - if item.ConfigId > 0 { - if item.Destination == util.Slack { - slackIds = append(slackIds, &item.ConfigId) - } else if item.Destination == util.SES { - sesUserIds = append(sesUserIds, int32(item.ConfigId)) - } else if item.Destination == util.SMTP { - smtpUserIds = append(smtpUserIds, int32(item.ConfigId)) - } else if item.Destination == util.Webhook { - webhookIds = append(webhookIds, &item.ConfigId) - } + if item.Destination == util.Slack { + slackIds = append(slackIds, &item.ConfigId) + } else if item.Destination == util.Webhook { + webhookIds = append(webhookIds, &item.ConfigId) } else { - providerConfigs = append(providerConfigs, &beans.ProvidersConfig{Dest: string(item.Destination), Recipient: item.Recipient}) + providerConfigs = append(providerConfigs, &beans.ProvidersConfig{Dest: string(item.Destination), Recipient: item.Recipient, Id: item.ConfigId}) } } if len(slackIds) > 0 { @@ -333,27 +324,6 @@ func (impl *NotificationConfigServiceImpl) BuildNotificationSettingsResponse(not providerConfigs = append(providerConfigs, &beans.ProvidersConfig{Id: item.Id, ConfigName: item.ConfigName, Dest: string(util.Webhook)}) } } - - if len(sesUserIds) > 0 { - sesConfigs, err := impl.userRepository.GetByIds(sesUserIds) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in fetching user", "sesUserIds", sesUserIds, "error", err) - return notificationSettingsResponses, deletedItemCount, err - } - for _, item := range sesConfigs { - providerConfigs = append(providerConfigs, &beans.ProvidersConfig{Id: int(item.Id), ConfigName: item.EmailId, Dest: string(util.SES)}) - } - } - if len(smtpUserIds) > 0 { - smtpConfigs, err := impl.userRepository.GetByIds(smtpUserIds) - if err != nil && err != pg.ErrNoRows { - impl.logger.Errorw("error in fetching user", "smtpUserIds", smtpUserIds, "error", err) - return notificationSettingsResponses, deletedItemCount, err - } - for _, item := range smtpConfigs { - providerConfigs = append(providerConfigs, &beans.ProvidersConfig{Id: int(item.Id), ConfigName: item.EmailId, Dest: string(util.SMTP)}) - } - } notificationSettingsResponse.ProvidersConfig = providerConfigs } diff --git a/pkg/notifier/SESNotificationService.go b/pkg/notifier/SESNotificationService.go index 7e5aee3bd7..324ffac9d0 100644 --- a/pkg/notifier/SESNotificationService.go +++ b/pkg/notifier/SESNotificationService.go @@ -60,6 +60,12 @@ func (impl *SESNotificationServiceImpl) SaveOrEditNotificationConfig(channelReq for _, config := range sesConfigs { if config.Id != 0 { + model, err := impl.sesRepository.FindOne(config.Id) + if err != nil && !util.IsErrNoRows(err) { + impl.logger.Errorw("err while fetching ses config", "err", err) + return []int{}, err + } + if config.Default { _, err := impl.sesRepository.UpdateSESConfigDefault() if err != nil && !util.IsErrNoRows(err) { @@ -67,6 +73,10 @@ func (impl *SESNotificationServiceImpl) SaveOrEditNotificationConfig(channelReq return []int{}, err } } else { + // check if this config is already default, we don't want to reverse it + if model.Default { + return []int{}, fmt.Errorf("cannot update default config to non default") + } _, err := impl.sesRepository.FindDefault() if err != nil && !util.IsErrNoRows(err) { impl.logger.Errorw("err while updating ses config", "err", err) @@ -76,11 +86,6 @@ func (impl *SESNotificationServiceImpl) SaveOrEditNotificationConfig(channelReq } } - model, err := impl.sesRepository.FindOne(config.Id) - if err != nil && !util.IsErrNoRows(err) { - impl.logger.Errorw("err while fetching ses config", "err", err) - return []int{}, err - } adapter.BuildConfigUpdateModelForSES(config, model, userId) model, uErr := impl.sesRepository.UpdateSESConfig(model) if uErr != nil { @@ -175,6 +180,10 @@ func (impl *SESNotificationServiceImpl) DeleteNotificationConfig(deleteReq *bean impl.logger.Errorw("found notifications using this config, cannot delete", "config", deleteReq) return fmt.Errorf(" Please delete all notifications using this config before deleting") } + // check if default then dont delete + if existingConfig.Default { + return fmt.Errorf("default configuration cannot be deleted") + } existingConfig.UpdatedOn = time.Now() existingConfig.UpdatedBy = userId //deleting slack config diff --git a/pkg/notifier/SMTPNotificationService.go b/pkg/notifier/SMTPNotificationService.go index 65e9eed08c..bcfa060739 100644 --- a/pkg/notifier/SMTPNotificationService.go +++ b/pkg/notifier/SMTPNotificationService.go @@ -60,6 +60,12 @@ func (impl *SMTPNotificationServiceImpl) SaveOrEditNotificationConfig(channelReq for _, config := range smtpConfigs { if config.Id != 0 { + model, err := impl.smtpRepository.FindOne(config.Id) + if err != nil && !util.IsErrNoRows(err) { + impl.logger.Errorw("err while fetching smtp config", "err", err) + return []int{}, err + } + if config.Default { _, err := impl.smtpRepository.UpdateSMTPConfigDefault() if err != nil && !util.IsErrNoRows(err) { @@ -67,6 +73,10 @@ func (impl *SMTPNotificationServiceImpl) SaveOrEditNotificationConfig(channelReq return []int{}, err } } else { + // check if this config is already default, we don't want to reverse it + if model.Default { + return []int{}, fmt.Errorf("cannot update default config to non default") + } _, err := impl.smtpRepository.FindDefault() if err != nil && !util.IsErrNoRows(err) { impl.logger.Errorw("err while updating smtp config", "err", err) @@ -76,11 +86,6 @@ func (impl *SMTPNotificationServiceImpl) SaveOrEditNotificationConfig(channelReq } } - model, err := impl.smtpRepository.FindOne(config.Id) - if err != nil && !util.IsErrNoRows(err) { - impl.logger.Errorw("err while fetching smtp config", "err", err) - return []int{}, err - } adapter.BuildConfigUpdateModelForSMTP(config, model, userId) model, uErr := impl.smtpRepository.UpdateSMTPConfig(model) if uErr != nil { @@ -175,6 +180,10 @@ func (impl *SMTPNotificationServiceImpl) DeleteNotificationConfig(deleteReq *bea impl.logger.Errorw("found notifications using this config, cannot delete", "config", deleteReq) return fmt.Errorf(" Please delete all notifications using this config before deleting") } + // check if default then dont delete + if existingConfig.Default { + return fmt.Errorf("default configuration cannot be deleted") + } existingConfig.UpdatedOn = time.Now() existingConfig.UpdatedBy = userId //deleting smtp config diff --git a/pkg/notifier/beans/beans.go b/pkg/notifier/beans/beans.go index 16c000ab86..5fc07dc32b 100644 --- a/pkg/notifier/beans/beans.go +++ b/pkg/notifier/beans/beans.go @@ -224,7 +224,6 @@ type NSDeleteRequest struct { type NotificationRequest struct { UpdateType util.UpdateType `json:"updateType,omitempty"` - SesConfigId int `json:"sesConfigId,omitempty"` Providers []*bean.Provider `json:"providers"` NotificationConfigRequest []*NotificationConfigRequest `json:"notificationConfigRequest" validate:"required"` } diff --git a/pkg/pipeline/CdHandler.go b/pkg/pipeline/CdHandler.go index 21196d5d60..1eddf62877 100644 --- a/pkg/pipeline/CdHandler.go +++ b/pkg/pipeline/CdHandler.go @@ -23,13 +23,18 @@ import ( "github.com/devtron-labs/common-lib/utils" bean4 "github.com/devtron-labs/common-lib/utils/bean" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/adapter/cdWorkflow" + cdWorkflow2 "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" bean2 "github.com/devtron-labs/devtron/pkg/bean" "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging" "github.com/devtron-labs/devtron/pkg/cluster/adapter" bean3 "github.com/devtron-labs/devtron/pkg/cluster/bean" repository3 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" common2 "github.com/devtron-labs/devtron/pkg/deployment/common" + "github.com/devtron-labs/devtron/pkg/pipeline/constants" util2 "github.com/devtron-labs/devtron/pkg/pipeline/util" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus" + bean5 "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/bean" + "github.com/devtron-labs/devtron/pkg/workflow/cd" "os" "path/filepath" "strconv" @@ -46,7 +51,6 @@ import ( "github.com/devtron-labs/devtron/pkg/auth/user" "github.com/devtron-labs/devtron/pkg/cluster" pipelineBean "github.com/devtron-labs/devtron/pkg/pipeline/bean" - "github.com/devtron-labs/devtron/pkg/pipeline/executors" "github.com/devtron-labs/devtron/pkg/pipeline/types" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" util3 "github.com/devtron-labs/devtron/util" @@ -64,7 +68,7 @@ const ( ) type CdHandler interface { - UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus) (int, string, error) + UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus) (int, string, bool, error) GetCdBuildHistory(appId int, environmentId int, pipelineId int, offset int, size int) ([]pipelineBean.CdWorkflowWithArtifact, error) GetRunningWorkflowLogs(environmentId int, pipelineId int, workflowId int) (*bufio.Reader, func() error, error) FetchCdWorkflowDetails(appId int, environmentId int, pipelineId int, buildId int) (types.WorkflowResponse, error) @@ -97,6 +101,8 @@ type CdHandlerImpl struct { blobConfigStorageService BlobStorageConfigService customTagService CustomTagService deploymentConfigService common2.DeploymentConfigService + workflowStageStatusService workflowStatus.WorkFlowStageStatusService + cdWorkflowRunnerService cd.CdWorkflowRunnerService } func NewCdHandlerImpl(Logger *zap.SugaredLogger, userService user.UserService, @@ -110,6 +116,8 @@ func NewCdHandlerImpl(Logger *zap.SugaredLogger, userService user.UserService, workflowService WorkflowService, clusterService cluster.ClusterService, blobConfigStorageService BlobStorageConfigService, customTagService CustomTagService, deploymentConfigService common2.DeploymentConfigService, + workflowStageStatusService workflowStatus.WorkFlowStageStatusService, + cdWorkflowRunnerService cd.CdWorkflowRunnerService, ) *CdHandlerImpl { cdh := &CdHandlerImpl{ Logger: Logger, @@ -130,6 +138,8 @@ func NewCdHandlerImpl(Logger *zap.SugaredLogger, userService user.UserService, blobConfigStorageService: blobConfigStorageService, customTagService: customTagService, deploymentConfigService: deploymentConfigService, + workflowStageStatusService: workflowStageStatusService, + cdWorkflowRunnerService: cdWorkflowRunnerService, } config, err := types.GetCdConfig() if err != nil { @@ -213,10 +223,10 @@ func (impl *CdHandlerImpl) CancelStage(workflowRunnerId int, forceAbort bool, us return 0, err } } - workflowRunner.Status = executors.WorkflowCancel + workflowRunner.Status = cdWorkflow2.WorkflowCancel workflowRunner.UpdatedOn = time.Now() workflowRunner.UpdatedBy = userId - err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(workflowRunner) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(workflowRunner) if err != nil { impl.Logger.Error("cannot update deleted workflow runner status, but wf deleted", "err", err) return 0, err @@ -225,10 +235,10 @@ func (impl *CdHandlerImpl) CancelStage(workflowRunnerId int, forceAbort bool, us } func (impl *CdHandlerImpl) updateWorkflowRunnerForForceAbort(workflowRunner *pipelineConfig.CdWorkflowRunner) error { - workflowRunner.Status = executors.WorkflowCancel + workflowRunner.Status = cdWorkflow2.WorkflowCancel workflowRunner.PodStatus = string(bean2.Failed) - workflowRunner.Message = FORCE_ABORT_MESSAGE_AFTER_STARTING_STAGE - err := impl.cdWorkflowRepository.UpdateWorkFlowRunner(workflowRunner) + workflowRunner.Message = constants.FORCE_ABORT_MESSAGE_AFTER_STARTING_STAGE + err := impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(workflowRunner) if err != nil { impl.Logger.Errorw("error in updating workflow status in cd workflow runner in force abort case", "err", err) return err @@ -252,29 +262,29 @@ func (impl *CdHandlerImpl) handleForceAbortCaseForCdStage(workflowRunner *pipeli return nil } -func (impl *CdHandlerImpl) UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus) (int, string, error) { +func (impl *CdHandlerImpl) UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus) (int, string, bool, error) { wfStatusRs := impl.extractWorkfowStatus(workflowStatus) workflowName, status, podStatus, message, podName := wfStatusRs.WorkflowName, wfStatusRs.Status, wfStatusRs.PodStatus, wfStatusRs.Message, wfStatusRs.PodName impl.Logger.Debugw("cd update for ", "wf ", workflowName, "status", status) if workflowName == "" { - return 0, "", errors.New("invalid wf name") + return 0, "", false, errors.New("invalid wf name") } workflowId, err := strconv.Atoi(workflowName[:strings.Index(workflowName, "-")]) if err != nil { impl.Logger.Error("invalid wf status update req", "err", err) - return 0, "", err + return 0, "", false, err } savedWorkflow, err := impl.cdWorkflowRepository.FindWorkflowRunnerById(workflowId) if err != nil { impl.Logger.Error("cannot get saved wf", "err", err) - return 0, "", err + return 0, "", false, err } cdArtifactLocationFormat := impl.config.GetArtifactLocationFormat() cdArtifactLocation := fmt.Sprintf(cdArtifactLocationFormat, savedWorkflow.CdWorkflowId, savedWorkflow.Id) if impl.stateChanged(status, podStatus, message, workflowStatus.FinishedAt.Time, savedWorkflow) { - if savedWorkflow.Status != executors.WorkflowCancel { + if savedWorkflow.Status != cdWorkflow2.WorkflowCancel { savedWorkflow.Status = status } savedWorkflow.CdArtifactLocation = cdArtifactLocation @@ -286,24 +296,25 @@ func (impl *CdHandlerImpl) UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus savedWorkflow.PodName = podName savedWorkflow.UpdateAuditLog(1) impl.Logger.Debugw("updating workflow ", "workflow", savedWorkflow) - err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(savedWorkflow) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(savedWorkflow) if err != nil { impl.Logger.Error("update wf failed for id " + strconv.Itoa(savedWorkflow.Id)) - return 0, "", err + return 0, "", true, err } appId := savedWorkflow.CdWorkflow.Pipeline.AppId envId := savedWorkflow.CdWorkflow.Pipeline.EnvironmentId envDeploymentConfig, err := impl.deploymentConfigService.GetConfigForDevtronApps(appId, envId) if err != nil { impl.Logger.Errorw("error in fetching environment deployment config by appId and envId", "appId", appId, "envId", envId, "err", err) - return 0, "", err + return 0, "", true, err } util3.TriggerCDMetrics(cdWorkflow.GetTriggerMetricsFromRunnerObj(savedWorkflow, envDeploymentConfig), impl.config.ExposeCDMetrics) if string(v1alpha1.NodeError) == savedWorkflow.Status || string(v1alpha1.NodeFailed) == savedWorkflow.Status { impl.Logger.Warnw("cd stage failed for workflow: ", "wfId", savedWorkflow.Id) } + return savedWorkflow.Id, savedWorkflow.Status, true, nil } - return savedWorkflow.Id, savedWorkflow.Status, nil + return savedWorkflow.Id, savedWorkflow.Status, false, nil } func (impl *CdHandlerImpl) extractWorkfowStatus(workflowStatus v1alpha1.WorkflowStatus) *types.WorkflowStatus { @@ -475,6 +486,29 @@ func (impl *CdHandlerImpl) GetCdBuildHistory(appId int, environmentId int, pipel } cdWorkflowArtifact[i] = item } + + //process pre/post cd stage data + //prepare a map of wfId and wf type to pass to next function + wfIdToWfTypeMap := make(map[int]pipelineBean.CdWorkflowWithArtifact) + for _, item := range cdWorkflowArtifact { + if item.WorkflowType == bean.CD_WORKFLOW_TYPE_PRE.String() || item.WorkflowType == bean.CD_WORKFLOW_TYPE_POST.String() { + wfIdToWfTypeMap[item.Id] = item + } + } + wfRunnerIdToStageDetailMap, err := impl.cdWorkflowRunnerService.GetPrePostWorkflowStagesByWorkflowRunnerIdsList(wfIdToWfTypeMap) + if err != nil { + impl.Logger.Errorw("error in fetching pre/post stage data", "err", err) + return cdWorkflowArtifact, err + } + + //now for each cdWorkflowArtifact, set the workflowStage Data from wfRunnerIdToStageDetailMap using workflowId as key wfRunnerIdToStageDetailMap + if len(wfRunnerIdToStageDetailMap) > 0 { + for i, item := range cdWorkflowArtifact { + if val, ok := wfRunnerIdToStageDetailMap[item.Id]; ok { + cdWorkflowArtifact[i].WorkflowExecutionStage = val + } + } + } return cdWorkflowArtifact, nil } @@ -520,7 +554,7 @@ func (impl *CdHandlerImpl) getWorkflowLogs(pipelineId int, cdWorkflow *pipelineC if logStream == nil || err != nil { if !cdWorkflow.BlobStorageEnabled { return nil, nil, errors.New("logs-not-stored-in-repository") - } else if string(v1alpha1.NodeSucceeded) == cdWorkflow.Status || string(v1alpha1.NodeError) == cdWorkflow.Status || string(v1alpha1.NodeFailed) == cdWorkflow.Status || cdWorkflow.Status == executors.WorkflowCancel { + } else if string(v1alpha1.NodeSucceeded) == cdWorkflow.Status || string(v1alpha1.NodeError) == cdWorkflow.Status || string(v1alpha1.NodeFailed) == cdWorkflow.Status || cdWorkflow.Status == cdWorkflow2.WorkflowCancel { impl.Logger.Debugw("pod is not live", "podName", cdWorkflow.PodName, "err", err) return impl.getLogsFromRepository(pipelineId, cdWorkflow, clusterConfig, runStageInEnv) } @@ -604,6 +638,19 @@ func (impl *CdHandlerImpl) FetchCdWorkflowDetails(appId int, environmentId int, } workflow := impl.converterWFR(*workflowR) + if workflowR.WorkflowType == bean.CD_WORKFLOW_TYPE_PRE || workflowR.WorkflowType == bean.CD_WORKFLOW_TYPE_POST { + //get execution stage data + impl.Logger.Infow("fetching pre/post workflow stages", "workflowId", workflowR.Id, "workflowType", workflowR.WorkflowType) + workflowStageData, err := impl.workflowStageStatusService.GetWorkflowStagesByWorkflowIdAndType(workflowR.Id, workflowR.WorkflowType.String()) + if err != nil { + impl.Logger.Errorw("error in fetching pre/post workflow stages", "err", err) + return types.WorkflowResponse{}, err + } + workflow.WorkflowExecutionStage = impl.workflowStageStatusService.ConvertDBWorkflowStageToMap(workflowStageData, workflow.Id, workflow.Status, workflow.PodStatus, workflow.Message, workflow.WorkflowType, workflow.StartedOn, workflow.FinishedOn) + } else { + workflow.WorkflowExecutionStage = map[string][]*bean5.WorkflowStageDto{} + } + triggeredByUserEmailId, err := impl.userService.GetActiveEmailById(workflow.TriggeredBy) if err != nil && !util.IsErrNoRows(err) { impl.Logger.Errorw("err", "err", err) @@ -658,27 +705,28 @@ func (impl *CdHandlerImpl) FetchCdWorkflowDetails(appId int, environmentId int, } workflowResponse := types.WorkflowResponse{ - Id: workflow.Id, - Name: workflow.Name, - Status: workflow.Status, - PodStatus: workflow.PodStatus, - Message: workflow.Message, - StartedOn: workflow.StartedOn, - FinishedOn: workflow.FinishedOn, - Namespace: workflow.Namespace, - CiMaterials: ciMaterialsArr, - TriggeredBy: workflow.TriggeredBy, - TriggeredByEmail: triggeredByUserEmailId, - Artifact: workflow.Image, - Stage: workflow.WorkflowType, - GitTriggers: gitTriggers, - BlobStorageEnabled: workflow.BlobStorageEnabled, - IsVirtualEnvironment: workflowR.CdWorkflow.Pipeline.Environment.IsVirtualEnvironment, - PodName: workflowR.PodName, - ArtifactId: workflow.CiArtifactId, - IsArtifactUploaded: workflow.IsArtifactUploaded, - CiPipelineId: ciWf.CiPipelineId, - TargetPlatforms: targetPlatforms, + Id: workflow.Id, + Name: workflow.Name, + Status: workflow.Status, + PodStatus: workflow.PodStatus, + Message: workflow.Message, + StartedOn: workflow.StartedOn, + FinishedOn: workflow.FinishedOn, + Namespace: workflow.Namespace, + CiMaterials: ciMaterialsArr, + TriggeredBy: workflow.TriggeredBy, + TriggeredByEmail: triggeredByUserEmailId, + Artifact: workflow.Image, + Stage: workflow.WorkflowType, + GitTriggers: gitTriggers, + BlobStorageEnabled: workflow.BlobStorageEnabled, + IsVirtualEnvironment: workflowR.CdWorkflow.Pipeline.Environment.IsVirtualEnvironment, + PodName: workflowR.PodName, + ArtifactId: workflow.CiArtifactId, + IsArtifactUploaded: workflow.IsArtifactUploaded, + CiPipelineId: ciWf.CiPipelineId, + TargetPlatforms: targetPlatforms, + WorkflowExecutionStage: workflow.WorkflowExecutionStage, } return workflowResponse, nil diff --git a/pkg/pipeline/CiHandler.go b/pkg/pipeline/CiHandler.go index b6b461f42a..2b37436c8b 100644 --- a/pkg/pipeline/CiHandler.go +++ b/pkg/pipeline/CiHandler.go @@ -32,7 +32,9 @@ import ( bean5 "github.com/devtron-labs/devtron/pkg/cluster/bean" "github.com/devtron-labs/devtron/pkg/cluster/environment" repository2 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" + constants2 "github.com/devtron-labs/devtron/pkg/pipeline/constants" util3 "github.com/devtron-labs/devtron/pkg/pipeline/util" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus" "io/ioutil" "net/http" "os" @@ -123,13 +125,15 @@ type CiHandlerImpl struct { clusterService cluster.ClusterService blobConfigStorageService BlobStorageConfigService envService environment.EnvironmentService + workFlowStageStatusService workflowStatus.WorkFlowStageStatusService } func NewCiHandlerImpl(Logger *zap.SugaredLogger, ciService CiService, ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository, gitSensorClient gitSensor.Client, ciWorkflowRepository pipelineConfig.CiWorkflowRepository, workflowService WorkflowService, ciLogService CiLogService, ciArtifactRepository repository.CiArtifactRepository, userService user.UserService, eventClient client.EventClient, eventFactory client.EventFactory, ciPipelineRepository pipelineConfig.CiPipelineRepository, appListingRepository repository.AppListingRepository, K8sUtil *k8s.K8sServiceImpl, cdPipelineRepository pipelineConfig.PipelineRepository, enforcerUtil rbac.EnforcerUtil, resourceGroupService resourceGroup.ResourceGroupService, envRepository repository2.EnvironmentRepository, imageTaggingService imageTagging.ImageTaggingService, k8sCommonService k8s2.K8sCommonService, clusterService cluster.ClusterService, blobConfigStorageService BlobStorageConfigService, appWorkflowRepository appWorkflow.AppWorkflowRepository, customTagService CustomTagService, - envService environment.EnvironmentService) *CiHandlerImpl { + envService environment.EnvironmentService, + workFlowStageStatusService workflowStatus.WorkFlowStageStatusService) *CiHandlerImpl { cih := &CiHandlerImpl{ Logger: Logger, ciService: ciService, @@ -156,6 +160,7 @@ func NewCiHandlerImpl(Logger *zap.SugaredLogger, ciService CiService, ciPipeline clusterService: clusterService, blobConfigStorageService: blobConfigStorageService, envService: envService, + workFlowStageStatusService: workFlowStageStatusService, } config, err := types.GetCiConfig() if err != nil { @@ -166,13 +171,6 @@ func NewCiHandlerImpl(Logger *zap.SugaredLogger, ciService CiService, ciPipeline return cih } -const DefaultCiWorkflowNamespace = "devtron-ci" -const Running = "Running" -const Starting = "Starting" -const POD_DELETED_MESSAGE = "pod deleted" -const TERMINATE_MESSAGE = "workflow shutdown with strategy: Terminate" -const FORCE_ABORT_MESSAGE_AFTER_STARTING_STAGE = "workflow shutdown with strategy: Force Abort" - func (impl *CiHandlerImpl) CheckAndReTriggerCI(workflowStatus v1alpha1.WorkflowStatus) error { //return if re-trigger feature is disabled @@ -192,6 +190,8 @@ func (impl *CiHandlerImpl) CheckAndReTriggerCI(workflowStatus v1alpha1.WorkflowS return nil } + impl.Logger.Debugw("re-triggering ci", "status", status, "message", message, "ciWorkflowStatus", ciWorkFlow.Status, "ciWorkFlowId", ciWorkFlow.Id) + retryCount, refCiWorkflow, err := impl.getRefWorkflowAndCiRetryCount(ciWorkFlow) if err != nil { impl.Logger.Errorw("error while getting retry count value for a ciWorkflow", "ciWorkFlowId", ciWorkFlow.Id) @@ -530,10 +530,19 @@ func (impl *CiHandlerImpl) GetBuildHistory(pipelineId int, appId int, offset int impl.Logger.Errorw("err", "err", err) return nil, err } + var workflowIds []int var artifactIds []int for _, w := range workFlows { artifactIds = append(artifactIds, w.CiArtifactId) + workflowIds = append(workflowIds, w.Id) + } + + allWfStagesDetail, err := impl.workFlowStageStatusService.GetWorkflowStagesByWorkflowIdsAndWfType(workflowIds, bean2.CI_WORKFLOW_TYPE.String()) + if err != nil { + impl.Logger.Errorw("error in fetching allWfStagesDetail", "err", err, "workflowIds", workflowIds) + return nil, err } + //this map contains artifactId -> imageComment of that artifact imageCommetnsDataMap, err := impl.imageTaggingService.GetImageCommentsDataMapByArtifactIds(artifactIds) if err != nil { @@ -550,29 +559,30 @@ func (impl *CiHandlerImpl) GetBuildHistory(pipelineId int, appId int, offset int isArtifactUploaded = w.IsArtifactUploaded } wfResponse := types.WorkflowResponse{ - Id: w.Id, - Name: w.Name, - Status: w.Status, - PodStatus: w.PodStatus, - Message: w.Message, - StartedOn: w.StartedOn, - FinishedOn: w.FinishedOn, - CiPipelineId: w.CiPipelineId, - Namespace: w.Namespace, - LogLocation: w.LogFilePath, - GitTriggers: w.GitTriggers, - CiMaterials: ciPipelineMaterialResponses, - Artifact: w.Image, - TriggeredBy: w.TriggeredBy, - TriggeredByEmail: w.EmailId, - ArtifactId: w.CiArtifactId, - BlobStorageEnabled: w.BlobStorageEnabled, - IsArtifactUploaded: isArtifactUploaded, - EnvironmentId: w.EnvironmentId, - EnvironmentName: w.EnvironmentName, - ReferenceWorkflowId: w.RefCiWorkflowId, - PodName: w.PodName, - TargetPlatforms: utils.ConvertTargetPlatformStringToObject(w.TargetPlatforms), + Id: w.Id, + Name: w.Name, + Status: w.Status, + PodStatus: w.PodStatus, + Message: w.Message, + StartedOn: w.StartedOn, + FinishedOn: w.FinishedOn, + CiPipelineId: w.CiPipelineId, + Namespace: w.Namespace, + LogLocation: w.LogFilePath, + GitTriggers: w.GitTriggers, + CiMaterials: ciPipelineMaterialResponses, + Artifact: w.Image, + TriggeredBy: w.TriggeredBy, + TriggeredByEmail: w.EmailId, + ArtifactId: w.CiArtifactId, + BlobStorageEnabled: w.BlobStorageEnabled, + IsArtifactUploaded: isArtifactUploaded, + EnvironmentId: w.EnvironmentId, + EnvironmentName: w.EnvironmentName, + ReferenceWorkflowId: w.RefCiWorkflowId, + PodName: w.PodName, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(w.TargetPlatforms), + WorkflowExecutionStage: impl.workFlowStageStatusService.ConvertDBWorkflowStageToMap(allWfStagesDetail, w.Id, w.Status, w.PodStatus, w.Message, bean2.CI_WORKFLOW_TYPE.String(), w.StartedOn, w.FinishedOn), } if w.Message == bean3.ImageTagUnavailableMessage { @@ -609,7 +619,7 @@ func (impl *CiHandlerImpl) CancelBuild(workflowId int, forceAbort bool) (int, er impl.Logger.Errorw("error in finding ci-workflow by workflow id", "ciWorkflowId", workflowId, "err", err) return 0, err } - isExt := workflow.Namespace != DefaultCiWorkflowNamespace + isExt := workflow.Namespace != constants2.DefaultCiWorkflowNamespace var env *repository2.Environment var restConfig *rest.Config if isExt { @@ -653,12 +663,12 @@ func (impl *CiHandlerImpl) CancelBuild(workflowId int, forceAbort bool) (int, er return workflow.Id, nil } - workflow.Status = executors.WorkflowCancel + workflow.Status = cdWorkflow.WorkflowCancel if workflow.ExecutorType == cdWorkflow.WORKFLOW_EXECUTOR_TYPE_SYSTEM { workflow.PodStatus = "Failed" - workflow.Message = TERMINATE_MESSAGE + workflow.Message = constants2.TERMINATE_MESSAGE } - err = impl.ciWorkflowRepository.UpdateWorkFlow(workflow) + err = impl.ciService.UpdateCiWorkflowWithStage(workflow) if err != nil { impl.Logger.Errorw("cannot update deleted workflow status, but wf deleted", "err", err) return 0, err @@ -697,10 +707,10 @@ func (impl *CiHandlerImpl) handleForceAbortCaseForCi(workflow *pipelineConfig.Ci } func (impl *CiHandlerImpl) updateWorkflowForForceAbort(workflow *pipelineConfig.CiWorkflow) error { - workflow.Status = executors.WorkflowCancel + workflow.Status = cdWorkflow.WorkflowCancel workflow.PodStatus = string(bean.Failed) - workflow.Message = FORCE_ABORT_MESSAGE_AFTER_STARTING_STAGE - err := impl.ciWorkflowRepository.UpdateWorkFlow(workflow) + workflow.Message = constants2.FORCE_ABORT_MESSAGE_AFTER_STARTING_STAGE + err := impl.ciService.UpdateCiWorkflowWithStage(workflow) if err != nil { impl.Logger.Errorw("error in updating workflow status", "err", err) return err @@ -783,30 +793,37 @@ func (impl *CiHandlerImpl) FetchWorkflowDetails(appId int, pipelineId int, build impl.ciWorkflowRepository.MigrateIsArtifactUploaded(workflow.Id, ciArtifact.IsArtifactUploaded) isArtifactUploaded = ciArtifact.IsArtifactUploaded } + wfStagesDetail, err := impl.workFlowStageStatusService.GetWorkflowStagesByWorkflowIdsAndWfType([]int{workflow.Id}, bean2.CI_WORKFLOW_TYPE.String()) + if err != nil { + impl.Logger.Errorw("error in fetching allWfStagesDetail", "err", err, "workflowId", workflow.Id) + return types.WorkflowResponse{}, err + } + workflowResponse := types.WorkflowResponse{ - Id: workflow.Id, - Name: workflow.Name, - Status: workflow.Status, - PodStatus: workflow.PodStatus, - Message: workflow.Message, - StartedOn: workflow.StartedOn, - FinishedOn: workflow.FinishedOn, - CiPipelineId: workflow.CiPipelineId, - Namespace: workflow.Namespace, - LogLocation: workflow.LogLocation, - BlobStorageEnabled: workflow.BlobStorageEnabled, //TODO default value if value not found in db - GitTriggers: workflow.GitTriggers, - CiMaterials: ciMaterialsArr, - TriggeredBy: workflow.TriggeredBy, - TriggeredByEmail: triggeredByUserEmailId, - Artifact: ciArtifact.Image, - TargetPlatforms: utils.ConvertTargetPlatformStringToObject(ciArtifact.TargetPlatforms), - ArtifactId: ciArtifact.Id, - IsArtifactUploaded: isArtifactUploaded, - EnvironmentId: workflow.EnvironmentId, - EnvironmentName: environmentName, - PipelineType: workflow.CiPipeline.PipelineType, - PodName: workflow.PodName, + Id: workflow.Id, + Name: workflow.Name, + Status: workflow.Status, + PodStatus: workflow.PodStatus, + Message: workflow.Message, + StartedOn: workflow.StartedOn, + FinishedOn: workflow.FinishedOn, + CiPipelineId: workflow.CiPipelineId, + Namespace: workflow.Namespace, + LogLocation: workflow.LogLocation, + BlobStorageEnabled: workflow.BlobStorageEnabled, //TODO default value if value not found in db + GitTriggers: workflow.GitTriggers, + CiMaterials: ciMaterialsArr, + TriggeredBy: workflow.TriggeredBy, + TriggeredByEmail: triggeredByUserEmailId, + Artifact: ciArtifact.Image, + TargetPlatforms: utils.ConvertTargetPlatformStringToObject(ciArtifact.TargetPlatforms), + ArtifactId: ciArtifact.Id, + IsArtifactUploaded: isArtifactUploaded, + EnvironmentId: workflow.EnvironmentId, + EnvironmentName: environmentName, + PipelineType: workflow.CiPipeline.PipelineType, + PodName: workflow.PodName, + WorkflowExecutionStage: impl.workFlowStageStatusService.ConvertDBWorkflowStageToMap(wfStagesDetail, workflow.Id, workflow.Status, workflow.PodStatus, workflow.Message, bean2.CI_WORKFLOW_TYPE.String(), workflow.StartedOn, workflow.FinishedOn), } return workflowResponse, nil } @@ -858,7 +875,7 @@ func (impl *CiHandlerImpl) getWorkflowLogs(ciWorkflow *pipelineConfig.CiWorkflow if logStream == nil || err != nil { if !ciWorkflow.BlobStorageEnabled { return nil, nil, &util.ApiError{Code: "200", HttpStatusCode: 400, UserMessage: "logs-not-stored-in-repository"} - } else if string(v1alpha1.NodeSucceeded) == ciWorkflow.Status || string(v1alpha1.NodeError) == ciWorkflow.Status || string(v1alpha1.NodeFailed) == ciWorkflow.Status || ciWorkflow.Status == executors.WorkflowCancel { + } else if string(v1alpha1.NodeSucceeded) == ciWorkflow.Status || string(v1alpha1.NodeError) == ciWorkflow.Status || string(v1alpha1.NodeFailed) == ciWorkflow.Status || ciWorkflow.Status == cdWorkflow.WorkflowCancel { impl.Logger.Debugw("pod is not live", "podName", ciWorkflow.PodName, "err", err) return impl.getLogsFromRepository(ciWorkflow, clusterConfig, isExt) } @@ -1181,7 +1198,7 @@ func (impl *CiHandlerImpl) UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus ciArtifactLocation := fmt.Sprintf(ciArtifactLocationFormat, savedWorkflow.Id, savedWorkflow.Id) if impl.stateChanged(status, podStatus, message, workflowStatus.FinishedAt.Time, savedWorkflow) { - if savedWorkflow.Status != executors.WorkflowCancel { + if savedWorkflow.Status != cdWorkflow.WorkflowCancel { savedWorkflow.Status = status } savedWorkflow.PodStatus = podStatus @@ -1190,9 +1207,9 @@ func (impl *CiHandlerImpl) UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus if len(message) > 250 { savedWorkflow.Message = message[:250] } - if savedWorkflow.ExecutorType == cdWorkflow.WORKFLOW_EXECUTOR_TYPE_SYSTEM && savedWorkflow.Status == executors.WorkflowCancel { + if savedWorkflow.ExecutorType == cdWorkflow.WORKFLOW_EXECUTOR_TYPE_SYSTEM && savedWorkflow.Status == cdWorkflow.WorkflowCancel { savedWorkflow.PodStatus = "Failed" - savedWorkflow.Message = TERMINATE_MESSAGE + savedWorkflow.Message = constants2.TERMINATE_MESSAGE } savedWorkflow.FinishedOn = workflowStatus.FinishedAt.Time savedWorkflow.Name = workflowName @@ -1201,22 +1218,30 @@ func (impl *CiHandlerImpl) UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus savedWorkflow.CiArtifactLocation = ciArtifactLocation savedWorkflow.PodName = podName impl.Logger.Debugw("updating workflow ", "workflow", savedWorkflow) - err = impl.ciWorkflowRepository.UpdateWorkFlow(savedWorkflow) + err = impl.ciService.UpdateCiWorkflowWithStage(savedWorkflow) if err != nil { impl.Logger.Error("update wf failed for id " + strconv.Itoa(savedWorkflow.Id)) return 0, err } - if string(v1alpha1.NodeError) == savedWorkflow.Status || string(v1alpha1.NodeFailed) == savedWorkflow.Status { - impl.Logger.Warnw("ci failed for workflow: ", "wfId", savedWorkflow.Id) + impl.sendCIFailEvent(savedWorkflow, status, message) + } + return savedWorkflow.Id, nil +} - if extractErrorCode(savedWorkflow.Message) != workFlow.CiStageFailErrorCode { - go impl.WriteCIFailEvent(savedWorkflow) - } else { - impl.Logger.Infof("Step failed notification received for wfID %d with message %s", savedWorkflow.Id, savedWorkflow.Message) - } +func (impl *CiHandlerImpl) sendCIFailEvent(savedWorkflow *pipelineConfig.CiWorkflow, status, message string) { + if string(v1alpha1.NodeError) == savedWorkflow.Status || string(v1alpha1.NodeFailed) == savedWorkflow.Status { + if executors.CheckIfReTriggerRequired(status, message, savedWorkflow.Status) { + impl.Logger.Infow("not sending failure notification for re-trigger workflow", "workflowId", savedWorkflow.Id) + return + } + impl.Logger.Warnw("ci failed for workflow: ", "wfId", savedWorkflow.Id) + + if extractErrorCode(savedWorkflow.Message) != workFlow.CiStageFailErrorCode { + go impl.WriteCIFailEvent(savedWorkflow) + } else { + impl.Logger.Infof("Step failed notification received for wfID %d with message %s", savedWorkflow.Id, savedWorkflow.Message) } } - return savedWorkflow.Id, nil } func extractErrorCode(msg string) int { @@ -1606,7 +1631,7 @@ func (impl *CiHandlerImpl) FetchMaterialInfoByArtifactId(ciArtifactId int, envId } func (impl *CiHandlerImpl) UpdateCiWorkflowStatusFailure(timeoutForFailureCiBuild int) error { - ciWorkflows, err := impl.ciWorkflowRepository.FindByStatusesIn([]string{Starting, Running}) + ciWorkflows, err := impl.ciWorkflowRepository.FindByStatusesIn([]string{constants2.Starting, constants2.Running}) if err != nil { impl.Logger.Errorw("error on fetching ci workflows", "err", err) return err @@ -1621,7 +1646,7 @@ func (impl *CiHandlerImpl) UpdateCiWorkflowStatusFailure(timeoutForFailureCiBuil var isExt bool var env *repository2.Environment var restConfig *rest.Config - if ciWorkflow.Namespace != DefaultCiWorkflowNamespace { + if ciWorkflow.Namespace != constants2.DefaultCiWorkflowNamespace { isExt = true env, err = impl.envRepository.FindById(ciWorkflow.EnvironmentId) if err != nil { @@ -1654,7 +1679,7 @@ func (impl *CiHandlerImpl) UpdateCiWorkflowStatusFailure(timeoutForFailureCiBuil //if ci workflow is exists, check its pod if !isEligibleToMarkFailed { - ns := DefaultCiWorkflowNamespace + ns := constants2.DefaultCiWorkflowNamespace if isExt { _, client, err = impl.k8sCommonService.GetCoreClientByClusterId(env.ClusterId) if err != nil { @@ -1681,7 +1706,7 @@ func (impl *CiHandlerImpl) UpdateCiWorkflowStatusFailure(timeoutForFailureCiBuil } } else { //check workflow status,get the status - if wf.Status == string(v1alpha1.WorkflowFailed) && wf.Message == POD_DELETED_MESSAGE { + if wf.Status == string(v1alpha1.WorkflowFailed) && wf.Message == constants2.POD_DELETED_MESSAGE { isPodDeleted = true } } @@ -1691,13 +1716,13 @@ func (impl *CiHandlerImpl) UpdateCiWorkflowStatusFailure(timeoutForFailureCiBuil ciWorkflow.Status = "Failed" ciWorkflow.PodStatus = "Failed" if isPodDeleted { - ciWorkflow.Message = executors.POD_DELETED_MESSAGE + ciWorkflow.Message = cdWorkflow.POD_DELETED_MESSAGE //error logging handled inside handlePodDeleted impl.handlePodDeleted(ciWorkflow) } else { ciWorkflow.Message = "marked failed by job" } - err := impl.ciWorkflowRepository.UpdateWorkFlow(ciWorkflow) + err := impl.ciService.UpdateCiWorkflowWithStage(ciWorkflow) if err != nil { impl.Logger.Errorw("unable to update ci workflow, its eligible to mark failed", "err", err) // skip this and process for next ci workflow diff --git a/pkg/pipeline/CiService.go b/pkg/pipeline/CiService.go index 1e5d309f19..d5282add0b 100644 --- a/pkg/pipeline/CiService.go +++ b/pkg/pipeline/CiService.go @@ -20,10 +20,12 @@ import ( "encoding/json" "errors" "fmt" + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/caarlos0/env" "github.com/devtron-labs/common-lib/utils" bean3 "github.com/devtron-labs/common-lib/utils/bean" commonBean "github.com/devtron-labs/common-lib/workflow" + bean5 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/internal/sql/constants" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" "github.com/devtron-labs/devtron/pkg/attributes" @@ -35,7 +37,10 @@ import ( "github.com/devtron-labs/devtron/pkg/pipeline/adapter" pipelineConst "github.com/devtron-labs/devtron/pkg/pipeline/constants" "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus" bean2 "github.com/devtron-labs/devtron/pkg/plugin/bean" + "github.com/devtron-labs/devtron/pkg/sql" + util3 "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/util/sliceUtil" "path" "path/filepath" @@ -74,6 +79,8 @@ import ( type CiService interface { TriggerCiPipeline(trigger types.Trigger) (int, error) GetCiMaterials(pipelineId int, ciMaterials []*pipelineConfig.CiPipelineMaterial) ([]*pipelineConfig.CiPipelineMaterial, error) + SaveCiWorkflowWithStage(wf *pipelineConfig.CiWorkflow) error + UpdateCiWorkflowWithStage(wf *pipelineConfig.CiWorkflow) error } type BuildxCacheFlags struct { BuildxCacheModeMin bool `env:"BUILDX_CACHE_MODE_MIN" envDefault:"false"` @@ -84,7 +91,7 @@ type CiServiceImpl struct { Logger *zap.SugaredLogger workflowService WorkflowService ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository - ciWorkflowRepository pipelineConfig.CiWorkflowRepository + workflowStageStatusService workflowStatus.WorkFlowStageStatusService eventClient client.EventClient eventFactory client.EventFactory ciPipelineRepository pipelineConfig.CiPipelineRepository @@ -104,11 +111,13 @@ type CiServiceImpl struct { ciCdPipelineOrchestrator CiCdPipelineOrchestrator buildxCacheFlags *BuildxCacheFlags attributeService attributes.AttributesService + ciWorkflowRepository pipelineConfig.CiWorkflowRepository + transactionManager sql.TransactionWrapper } func NewCiServiceImpl(Logger *zap.SugaredLogger, workflowService WorkflowService, ciPipelineMaterialRepository pipelineConfig.CiPipelineMaterialRepository, - ciWorkflowRepository pipelineConfig.CiWorkflowRepository, eventClient client.EventClient, + workflowStageStatusService workflowStatus.WorkFlowStageStatusService, eventClient client.EventClient, eventFactory client.EventFactory, ciPipelineRepository pipelineConfig.CiPipelineRepository, ciArtifactRepository repository5.CiArtifactRepository, @@ -121,6 +130,8 @@ func NewCiServiceImpl(Logger *zap.SugaredLogger, workflowService WorkflowService globalPluginService plugin.GlobalPluginService, infraProvider infraProviders.InfraProvider, ciCdPipelineOrchestrator CiCdPipelineOrchestrator, attributeService attributes.AttributesService, + ciWorkflowRepository pipelineConfig.CiWorkflowRepository, + transactionManager sql.TransactionWrapper, ) *CiServiceImpl { buildxCacheFlags := &BuildxCacheFlags{} err := env.Parse(buildxCacheFlags) @@ -131,7 +142,7 @@ func NewCiServiceImpl(Logger *zap.SugaredLogger, workflowService WorkflowService Logger: Logger, workflowService: workflowService, ciPipelineMaterialRepository: ciPipelineMaterialRepository, - ciWorkflowRepository: ciWorkflowRepository, + workflowStageStatusService: workflowStageStatusService, eventClient: eventClient, eventFactory: eventFactory, ciPipelineRepository: ciPipelineRepository, @@ -150,6 +161,8 @@ func NewCiServiceImpl(Logger *zap.SugaredLogger, workflowService WorkflowService ciCdPipelineOrchestrator: ciCdPipelineOrchestrator, buildxCacheFlags: buildxCacheFlags, attributeService: attributeService, + ciWorkflowRepository: ciWorkflowRepository, + transactionManager: transactionManager, } config, err := types.GetCiConfig() if err != nil { @@ -257,9 +270,9 @@ func (impl *CiServiceImpl) markCurrentCiWorkflowFailed(savedCiWf *pipelineConfig var dbErr error if savedCiWf.Id == 0 { - dbErr = impl.ciWorkflowRepository.SaveWorkFlow(savedCiWf) + dbErr = impl.SaveCiWorkflowWithStage(savedCiWf) } else { - dbErr = impl.ciWorkflowRepository.UpdateWorkFlow(savedCiWf) + dbErr = impl.UpdateCiWorkflowWithStage(savedCiWf) } if dbErr != nil { @@ -364,7 +377,7 @@ func (impl *CiServiceImpl) TriggerCiPipeline(trigger types.Trigger) (int, error) if err != nil { savedCiWf.Status = cdWorkflow.WorkflowAborted savedCiWf.Message = err.Error() - err1 := impl.ciWorkflowRepository.UpdateWorkFlow(savedCiWf) + err1 := impl.UpdateCiWorkflowWithStage(savedCiWf) if err1 != nil { impl.Logger.Errorw("could not save workflow, after failing due to conflicting image tag") } @@ -519,7 +532,7 @@ func (impl *CiServiceImpl) saveNewWorkflow(pipeline *pipelineConfig.CiPipeline, ciWorkflow.Namespace = ciWorkflowConfigNamespace ciWorkflow.EnvironmentId = EnvironmentId } - err := impl.ciWorkflowRepository.SaveWorkFlow(ciWorkflow) + err := impl.SaveCiWorkflowWithStage(ciWorkflow) if err != nil { impl.Logger.Errorw("saving workflow error", "err", err) return &pipelineConfig.CiWorkflow{}, err @@ -1104,7 +1117,7 @@ func (impl *CiServiceImpl) updateCiWorkflow(request *types.WorkflowRequest, save ciBuildConfig := request.CiBuildConfig ciBuildType := string(ciBuildConfig.CiBuildType) savedWf.CiBuildType = ciBuildType - return impl.ciWorkflowRepository.UpdateWorkFlow(savedWf) + return impl.UpdateCiWorkflowWithStage(savedWf) } func _getTruncatedImageTag(imageTag string) string { @@ -1121,3 +1134,78 @@ func _getTruncatedImageTag(imageTag string) string { return imageTag[:_truncatedLength] } } + +func (impl *CiServiceImpl) SaveCiWorkflowWithStage(wf *pipelineConfig.CiWorkflow) error { + // implementation + tx, err := impl.transactionManager.StartTx() + if err != nil { + impl.Logger.Errorw("error in starting transaction to save default configurations", "workflowName", wf.Name, "error", err) + return err + } + + defer func() { + dbErr := impl.transactionManager.RollbackTx(tx) + if dbErr != nil && dbErr.Error() != util3.SqlAlreadyCommitedErrMsg { + impl.Logger.Errorw("error in rolling back transaction", "workflowName", wf.Name, "error", dbErr) + } + }() + if impl.config.EnableWorkflowExecutionStage { + wf.Status = cdWorkflow.WorkflowWaitingToStart + wf.PodStatus = string(v1alpha1.NodePending) + } + err = impl.ciWorkflowRepository.SaveWorkFlowWithTx(wf, tx) + if err != nil { + impl.Logger.Errorw("error in saving workflow", "payload", wf, "error", err) + return err + } + + err = impl.workflowStageStatusService.SaveWorkflowStages(wf.Id, bean5.CI_WORKFLOW_TYPE.String(), wf.Name, tx) + if err != nil { + impl.Logger.Errorw("error in saving workflow stages", "workflowName", wf.Name, "error", err) + return err + } + + err = impl.transactionManager.CommitTx(tx) + if err != nil { + impl.Logger.Errorw("error in committing transaction", "workflowName", wf.Name, "error", err) + return err + } + return nil + +} + +func (impl *CiServiceImpl) UpdateCiWorkflowWithStage(wf *pipelineConfig.CiWorkflow) error { + // implementation + tx, err := impl.transactionManager.StartTx() + if err != nil { + impl.Logger.Errorw("error in starting transaction to save default configurations", "workflowName", wf.Name, "error", err) + return err + } + + defer func() { + dbErr := impl.transactionManager.RollbackTx(tx) + if dbErr != nil && dbErr.Error() != util3.SqlAlreadyCommitedErrMsg { + impl.Logger.Errorw("error in rolling back transaction", "workflowName", wf.Name, "error", dbErr) + } + }() + + wf.Status, wf.PodStatus, err = impl.workflowStageStatusService.UpdateWorkflowStages(wf.Id, bean5.CI_WORKFLOW_TYPE.String(), wf.Name, wf.Status, wf.PodStatus, wf.Message, wf.PodName, tx) + if err != nil { + impl.Logger.Errorw("error in updating workflow stages", "workflowName", wf.Name, "error", err) + return err + } + + err = impl.ciWorkflowRepository.UpdateWorkFlowWithTx(wf, tx) + if err != nil { + impl.Logger.Errorw("error in saving workflow", "payload", wf, "error", err) + return err + } + + err = impl.transactionManager.CommitTx(tx) + if err != nil { + impl.Logger.Errorw("error in committing transaction", "workflowName", wf.Name, "error", err) + return err + } + return nil + +} diff --git a/pkg/pipeline/WebhookService.go b/pkg/pipeline/WebhookService.go index 5b4b3446f6..2fcdb828de 100644 --- a/pkg/pipeline/WebhookService.go +++ b/pkg/pipeline/WebhookService.go @@ -27,6 +27,7 @@ import ( "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/pkg/pipeline/bean" types2 "github.com/devtron-labs/devtron/pkg/pipeline/types" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus" "github.com/devtron-labs/devtron/pkg/workflow/cd" util3 "github.com/devtron-labs/devtron/util" "go.uber.org/zap" @@ -76,24 +77,30 @@ type WebhookService interface { } type WebhookServiceImpl struct { - ciArtifactRepository repository.CiArtifactRepository - ciConfig *types2.CiConfig - logger *zap.SugaredLogger - ciPipelineRepository pipelineConfig.CiPipelineRepository - ciWorkflowRepository pipelineConfig.CiWorkflowRepository - cdWorkflowCommonService cd.CdWorkflowCommonService + ciArtifactRepository repository.CiArtifactRepository + ciConfig *types2.CiConfig + logger *zap.SugaredLogger + ciPipelineRepository pipelineConfig.CiPipelineRepository + ciWorkflowRepository pipelineConfig.CiWorkflowRepository + cdWorkflowCommonService cd.CdWorkflowCommonService + workFlowStageStatusService workflowStatus.WorkFlowStageStatusService + ciService CiService } func NewWebhookServiceImpl(ciArtifactRepository repository.CiArtifactRepository, logger *zap.SugaredLogger, ciPipelineRepository pipelineConfig.CiPipelineRepository, ciWorkflowRepository pipelineConfig.CiWorkflowRepository, - cdWorkflowCommonService cd.CdWorkflowCommonService) *WebhookServiceImpl { + cdWorkflowCommonService cd.CdWorkflowCommonService, + workFlowStageStatusService workflowStatus.WorkFlowStageStatusService, + ciService CiService) *WebhookServiceImpl { webhookHandler := &WebhookServiceImpl{ - ciArtifactRepository: ciArtifactRepository, - logger: logger, - ciPipelineRepository: ciPipelineRepository, - ciWorkflowRepository: ciWorkflowRepository, - cdWorkflowCommonService: cdWorkflowCommonService, + ciArtifactRepository: ciArtifactRepository, + logger: logger, + ciPipelineRepository: ciPipelineRepository, + ciWorkflowRepository: ciWorkflowRepository, + cdWorkflowCommonService: cdWorkflowCommonService, + workFlowStageStatusService: workFlowStageStatusService, + ciService: ciService, } config, err := types2.GetCiConfig() if err != nil { @@ -161,7 +168,7 @@ func (impl *WebhookServiceImpl) HandleMultipleImagesFromEvent(imageDetails []*re GitTriggers: ciWorkflow.GitTriggers, Message: ciWorkflow.Message, } - err = impl.ciWorkflowRepository.SaveWorkFlow(workflow) + err = impl.ciService.SaveCiWorkflowWithStage(workflow) if err != nil { impl.logger.Errorw("error in saving workflow for child workflow", "err", err, "parentCiWorkflowId", ciWorkflowId) return nil, err diff --git a/pkg/pipeline/bean/CdHandlerBean.go b/pkg/pipeline/bean/CdHandlerBean.go index a3118943d6..4b6480e365 100644 --- a/pkg/pipeline/bean/CdHandlerBean.go +++ b/pkg/pipeline/bean/CdHandlerBean.go @@ -4,35 +4,37 @@ import ( "github.com/devtron-labs/common-lib/utils/bean" "github.com/devtron-labs/devtron/internal/sql/repository/imageTagging" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" + bean2 "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/bean" "time" ) type CdWorkflowWithArtifact struct { - Id int `json:"id"` - CdWorkflowId int `json:"cd_workflow_id"` - Name string `json:"name"` - Status string `json:"status"` - PodStatus string `json:"pod_status"` - Message string `json:"message"` - StartedOn time.Time `json:"started_on"` - FinishedOn time.Time `json:"finished_on"` - PipelineId int `json:"pipeline_id"` - Namespace string `json:"namespace"` - LogFilePath string `json:"log_file_path"` - TriggeredBy int32 `json:"triggered_by"` - EmailId string `json:"email_id"` - Image string `json:"image"` - TargetPlatforms []*bean.TargetPlatform `json:"targetPlatforms"` - MaterialInfo string `json:"material_info,omitempty"` - DataSource string `json:"data_source,omitempty"` - CiArtifactId int `json:"ci_artifact_id,omitempty"` - IsArtifactUploaded bool `json:"isArtifactUploaded"` - WorkflowType string `json:"workflow_type,omitempty"` - ExecutorType string `json:"executor_type,omitempty"` - BlobStorageEnabled bool `json:"blobStorageEnabled"` - GitTriggers map[int]pipelineConfig.GitCommit `json:"gitTriggers"` - CiMaterials []pipelineConfig.CiPipelineMaterialResponse `json:"ciMaterials"` - ImageReleaseTags []*repository.ImageTag `json:"imageReleaseTags"` - ImageComment *repository.ImageComment `json:"imageComment"` - RefCdWorkflowRunnerId int `json:"referenceCdWorkflowRunnerId"` + Id int `json:"id"` + CdWorkflowId int `json:"cd_workflow_id"` + Name string `json:"name"` + Status string `json:"status"` + PodStatus string `json:"pod_status"` + Message string `json:"message"` + StartedOn time.Time `json:"started_on"` + FinishedOn time.Time `json:"finished_on"` + PipelineId int `json:"pipeline_id"` + Namespace string `json:"namespace"` + LogFilePath string `json:"log_file_path"` + TriggeredBy int32 `json:"triggered_by"` + EmailId string `json:"email_id"` + Image string `json:"image"` + TargetPlatforms []*bean.TargetPlatform `json:"targetPlatforms"` + MaterialInfo string `json:"material_info,omitempty"` + DataSource string `json:"data_source,omitempty"` + CiArtifactId int `json:"ci_artifact_id,omitempty"` + IsArtifactUploaded bool `json:"isArtifactUploaded"` + WorkflowType string `json:"workflow_type,omitempty"` + ExecutorType string `json:"executor_type,omitempty"` + BlobStorageEnabled bool `json:"blobStorageEnabled"` + GitTriggers map[int]pipelineConfig.GitCommit `json:"gitTriggers"` + CiMaterials []pipelineConfig.CiPipelineMaterialResponse `json:"ciMaterials"` + ImageReleaseTags []*repository.ImageTag `json:"imageReleaseTags"` + ImageComment *repository.ImageComment `json:"imageComment"` + RefCdWorkflowRunnerId int `json:"referenceCdWorkflowRunnerId"` + WorkflowExecutionStage map[string][]*bean2.WorkflowStageDto `json:"workflowExecutionStages"` } diff --git a/pkg/pipeline/constants/constants.go b/pkg/pipeline/constants/constants.go index 823fbe1689..0d5cd5bcab 100644 --- a/pkg/pipeline/constants/constants.go +++ b/pkg/pipeline/constants/constants.go @@ -64,3 +64,11 @@ const ( ExtraEnvVarExternalCiArtifactKey = "externalCiArtifact" ExtraEnvVarImageDigestKey = "imageDigest" ) + +const DefaultCiWorkflowNamespace = "devtron-ci" +const Running = "Running" +const Starting = "Starting" +const POD_DELETED_MESSAGE = "pod deleted" +const TERMINATE_MESSAGE = "workflow shutdown with strategy: Terminate" +const FORCE_ABORT_MESSAGE_AFTER_STARTING_STAGE = "workflow shutdown with strategy: Force Abort" +const POD_TIMEOUT_MESSAGE = "Pod was active on the node longer than the specified deadline" diff --git a/pkg/pipeline/executors/WorkflowUtils.go b/pkg/pipeline/executors/WorkflowUtils.go index ed2aae3e98..0c9f18e911 100644 --- a/pkg/pipeline/executors/WorkflowUtils.go +++ b/pkg/pipeline/executors/WorkflowUtils.go @@ -24,6 +24,7 @@ import ( "github.com/devtron-labs/common-lib/utils" bean2 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/internal/sql/repository" + "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" "github.com/devtron-labs/devtron/pkg/pipeline/bean" "github.com/devtron-labs/devtron/pkg/pipeline/types" "github.com/devtron-labs/devtron/util" @@ -287,13 +288,10 @@ func GetClientInstance(config *rest.Config, namespace string) (v1alpha12.Workflo func CheckIfReTriggerRequired(status, message, workflowRunnerStatus string) bool { return ((status == string(v1alpha1.NodeError) || status == string(v1alpha1.NodeFailed)) && - message == POD_DELETED_MESSAGE) && workflowRunnerStatus != WorkflowCancel + message == cdWorkflow.POD_DELETED_MESSAGE) && (workflowRunnerStatus != cdWorkflow.WorkflowCancel && workflowRunnerStatus != cdWorkflow.WorkflowAborted) } -const WorkflowCancel = "CANCELLED" -const POD_DELETED_MESSAGE = "pod deleted" - func GetWorkflowLabelsForSystemExecutor(workflowTemplate bean.WorkflowTemplate) map[string]string { return map[string]string{ DEVTRON_WORKFLOW_LABEL_KEY: DEVTRON_WORKFLOW_LABEL_VALUE, diff --git a/pkg/pipeline/types/CiCdConfig.go b/pkg/pipeline/types/CiCdConfig.go index e404009518..961bd9f26f 100644 --- a/pkg/pipeline/types/CiCdConfig.go +++ b/pkg/pipeline/types/CiCdConfig.go @@ -160,6 +160,7 @@ type CiCdConfig struct { UseArtifactListingQueryV2 bool `env:"USE_ARTIFACT_LISTING_QUERY_V2" envDefault:"true"` UseImageTagFromGitProviderForTagBasedBuild bool `env:"USE_IMAGE_TAG_FROM_GIT_PROVIDER_FOR_TAG_BASED_BUILD" envDefault:"false"` // this is being done for https://github.com/devtron-labs/devtron/issues/4263 UseDockerApiToGetDigest bool `env:"USE_DOCKER_API_TO_GET_DIGEST" envDefault:"false"` + EnableWorkflowExecutionStage bool `env:"ENABLE_WORKFLOW_EXECUTION_STAGE" envDefault:"true" description:"if enabled then we will display build stages separately for CI/Job/Pre-Post CD" example:"true"` } type CiConfig struct { diff --git a/pkg/pipeline/types/Workflow.go b/pkg/pipeline/types/Workflow.go index 914c732944..dca45ab8fc 100644 --- a/pkg/pipeline/types/Workflow.go +++ b/pkg/pipeline/types/Workflow.go @@ -34,6 +34,7 @@ import ( repository4 "github.com/devtron-labs/devtron/pkg/cluster/environment/repository" infraBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean/v1" "github.com/devtron-labs/devtron/pkg/pipeline/bean" + bean6 "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/bean" bean4 "github.com/devtron-labs/devtron/pkg/plugin/bean" "github.com/devtron-labs/devtron/pkg/resourceQualifiers" "k8s.io/api/core/v1" @@ -648,36 +649,37 @@ type ChildCdMetadata struct { } type WorkflowResponse struct { - Id int `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - PodStatus string `json:"podStatus"` - Message string `json:"message"` - StartedOn time.Time `json:"startedOn"` - FinishedOn time.Time `json:"finishedOn"` - CiPipelineId int `json:"ciPipelineId"` - Namespace string `json:"namespace"` - LogLocation string `json:"logLocation"` - BlobStorageEnabled bool `json:"blobStorageEnabled"` - GitTriggers map[int]pipelineConfig.GitCommit `json:"gitTriggers"` - CiMaterials []pipelineConfig.CiPipelineMaterialResponse `json:"ciMaterials"` - TriggeredBy int32 `json:"triggeredBy"` - Artifact string `json:"artifact"` - TriggeredByEmail string `json:"triggeredByEmail"` - Stage string `json:"stage"` - ArtifactId int `json:"artifactId"` - IsArtifactUploaded bool `json:"isArtifactUploaded"` - IsVirtualEnvironment bool `json:"isVirtualEnvironment"` - PodName string `json:"podName"` - EnvironmentId int `json:"environmentId"` - EnvironmentName string `json:"environmentName"` - ImageReleaseTags []*repository3.ImageTag `json:"imageReleaseTags"` - ImageComment *repository3.ImageComment `json:"imageComment"` - AppWorkflowId int `json:"appWorkflowId"` - CustomTag *bean3.CustomTagErrorResponse `json:"customTag,omitempty"` - PipelineType string `json:"pipelineType"` - ReferenceWorkflowId int `json:"referenceWorkflowId"` - TargetPlatforms []*bean7.TargetPlatform `json:"targetPlatforms"` + Id int `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + PodStatus string `json:"podStatus"` + Message string `json:"message"` + StartedOn time.Time `json:"startedOn"` + FinishedOn time.Time `json:"finishedOn"` + CiPipelineId int `json:"ciPipelineId"` + Namespace string `json:"namespace"` + LogLocation string `json:"logLocation"` + BlobStorageEnabled bool `json:"blobStorageEnabled"` + GitTriggers map[int]pipelineConfig.GitCommit `json:"gitTriggers"` + CiMaterials []pipelineConfig.CiPipelineMaterialResponse `json:"ciMaterials"` + TriggeredBy int32 `json:"triggeredBy"` + Artifact string `json:"artifact"` + TriggeredByEmail string `json:"triggeredByEmail"` + Stage string `json:"stage"` + ArtifactId int `json:"artifactId"` + IsArtifactUploaded bool `json:"isArtifactUploaded"` + IsVirtualEnvironment bool `json:"isVirtualEnvironment"` + PodName string `json:"podName"` + EnvironmentId int `json:"environmentId"` + EnvironmentName string `json:"environmentName"` + ImageReleaseTags []*repository3.ImageTag `json:"imageReleaseTags"` + ImageComment *repository3.ImageComment `json:"imageComment"` + AppWorkflowId int `json:"appWorkflowId"` + CustomTag *bean3.CustomTagErrorResponse `json:"customTag,omitempty"` + PipelineType string `json:"pipelineType"` + ReferenceWorkflowId int `json:"referenceWorkflowId"` + TargetPlatforms []*bean7.TargetPlatform `json:"targetPlatforms"` + WorkflowExecutionStage map[string][]*bean6.WorkflowStageDto `json:"workflowExecutionStages"` } type ConfigMapSecretDto struct { diff --git a/pkg/pipeline/workflowStatus/WorkflowStageStatusService.go b/pkg/pipeline/workflowStatus/WorkflowStageStatusService.go new file mode 100644 index 0000000000..d583ef9261 --- /dev/null +++ b/pkg/pipeline/workflowStatus/WorkflowStageStatusService.go @@ -0,0 +1,393 @@ +package workflowStatus + +import ( + "encoding/json" + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" + "github.com/devtron-labs/devtron/api/bean" + "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" + "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" + bean3 "github.com/devtron-labs/devtron/pkg/bean" + "github.com/devtron-labs/devtron/pkg/pipeline/constants" + "github.com/devtron-labs/devtron/pkg/pipeline/types" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/adapter" + bean2 "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/bean" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/repository" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/util" + "github.com/devtron-labs/devtron/pkg/sql" + "github.com/go-pg/pg" + "go.uber.org/zap" + "slices" + "strings" + "time" +) + +type WorkFlowStageStatusService interface { + GetWorkflowStagesByWorkflowIdsAndWfType(wfIds []int, wfType string) ([]*repository.WorkflowExecutionStage, error) + GetWorkflowStagesByWorkflowIdAndType(wfId int, wfType string) ([]*repository.WorkflowExecutionStage, error) + + SaveWorkflowStages(wfId int, wfType, wfName string, tx *pg.Tx) error + UpdateWorkflowStages(wfId int, wfType, wfName, wfStatus, podStatus, message, podName string, tx *pg.Tx) (string, string, error) + ConvertDBWorkflowStageToMap(workflowStages []*repository.WorkflowExecutionStage, wfId int, status, podStatus, message, wfType string, startTime, endTime time.Time) map[string][]*bean2.WorkflowStageDto +} + +type WorkFlowStageStatusServiceImpl struct { + logger *zap.SugaredLogger + workflowStatusRepository repository.WorkflowStageRepository + ciWorkflowRepository pipelineConfig.CiWorkflowRepository + cdWorkflowRepository pipelineConfig.CdWorkflowRepository + transactionManager sql.TransactionWrapper + config *types.CiConfig +} + +func NewWorkflowStageFlowStatusServiceImpl(logger *zap.SugaredLogger, + workflowStatusRepository repository.WorkflowStageRepository, + ciWorkflowRepository pipelineConfig.CiWorkflowRepository, + cdWorkflowRepository pipelineConfig.CdWorkflowRepository, + transactionManager sql.TransactionWrapper, +) *WorkFlowStageStatusServiceImpl { + wfStageServiceImpl := &WorkFlowStageStatusServiceImpl{ + logger: logger, + workflowStatusRepository: workflowStatusRepository, + ciWorkflowRepository: ciWorkflowRepository, + cdWorkflowRepository: cdWorkflowRepository, + transactionManager: transactionManager, + } + ciConfig, err := types.GetCiConfig() + if err != nil { + return nil + } + wfStageServiceImpl.config = ciConfig + return wfStageServiceImpl +} + +func (impl *WorkFlowStageStatusServiceImpl) getUpdatedPipelineStagesForWorkflow(wfId int, wfType string, wfStatus string, podStatus string, message string, podName string) ([]*repository.WorkflowExecutionStage, string, string) { + // implementation + currentWorkflowStages, err := impl.workflowStatusRepository.GetWorkflowStagesByWorkflowIdAndType(wfId, wfType) + if err != nil { + impl.logger.Errorw("error in getting workflow stages", "workflowId", wfId, "error", err) + return nil, wfStatus, podStatus + } + if len(currentWorkflowStages) == 0 { + return []*repository.WorkflowExecutionStage{}, wfStatus, podStatus + } + + var currentWfDBstatus, currentPodStatus string + + if wfType == bean.CI_WORKFLOW_TYPE.String() { + //get current status from db + dbWf, err := impl.ciWorkflowRepository.FindById(wfId) + if err != nil { + impl.logger.Errorw("error in getting workflow", "wfId", wfId, "error", err) + return nil, wfStatus, podStatus + } + currentWfDBstatus = dbWf.Status + currentPodStatus = dbWf.PodStatus + } else { + dbWfr, err := impl.cdWorkflowRepository.FindWorkflowRunnerById(wfId) + if err != nil { + impl.logger.Errorw("error in getting workflow runner", "wfId", wfId, "error", err) + return nil, wfStatus, podStatus + } + currentWfDBstatus = dbWfr.Status + currentPodStatus = dbWfr.PodStatus + } + + impl.logger.Infow("step-1", "wfId", wfId, "wfType", wfType, "wfStatus", wfStatus, "currentWfDBstatus", currentWfDBstatus, "podStatus", podStatus, "currentPodStatus", currentPodStatus, "message", message) + currentWorkflowStages, updatedPodStatus := impl.updatePodStages(currentWorkflowStages, podStatus, currentPodStatus, message, podName, wfStatus) + impl.logger.Infow("step-2", "updatedPodStatus", updatedPodStatus, "updated pod stages", currentWorkflowStages) + currentWorkflowStages, updatedWfStatus := impl.updateWorkflowStagesToDevtronStatus(currentWorkflowStages, wfStatus, currentWfDBstatus, message, podStatus) + impl.logger.Infow("step-3", "updatedWfStatus", updatedWfStatus, "updatedPodStatus", updatedPodStatus, "updated workflow stages", currentWorkflowStages) + + return currentWorkflowStages, updatedWfStatus, updatedPodStatus +} + +func (impl *WorkFlowStageStatusServiceImpl) updatePodStages(currentWorkflowStages []*repository.WorkflowExecutionStage, podStatus string, currentPodStatus string, message string, podName string, wfStatus string) ([]*repository.WorkflowExecutionStage, string) { + updatedPodStatus := currentPodStatus + if !slices.Contains(cdWorkflow.WfrTerminalStatusList, currentPodStatus) { + updatedPodStatus = podStatus + } + //update pod stage status by using convertPodStatusToDevtronStatus + for _, stage := range currentWorkflowStages { + if stage.StatusFor == bean2.WORKFLOW_STAGE_STATUS_TYPE_POD { + // add pod name in stage metadata if not empty + if len(podName) > 0 { + marshalledMetadata, _ := json.Marshal(map[string]string{"podName": podName}) + stage.Metadata = string(marshalledMetadata) + } + switch podStatus { + case string(v1alpha1.NodePending): + if !stage.Status.IsTerminal() { + stage.Message = message + stage.Status = bean2.WORKFLOW_STAGE_STATUS_NOT_STARTED + } + case string(v1alpha1.NodeRunning): + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_NOT_STARTED || + stage.Status == bean2.WORKFLOW_STAGE_STATUS_UNKNOWN { + stage.Message = message + stage.Status = bean2.WORKFLOW_STAGE_STATUS_RUNNING + stage.StartTime = time.Now().Format(bean3.LayoutRFC3339) + } + case string(v1alpha1.NodeSucceeded): + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_RUNNING || + stage.Status == bean2.WORKFLOW_STAGE_STATUS_UNKNOWN { + stage.Message = message + stage.Status = bean2.WORKFLOW_STAGE_STATUS_SUCCEEDED + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + } + case string(v1alpha1.NodeFailed), string(v1alpha1.NodeError), string(v1alpha1.NodeSkipped): + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_RUNNING || + stage.Status == bean2.WORKFLOW_STAGE_STATUS_NOT_STARTED || + stage.Status == bean2.WORKFLOW_STAGE_STATUS_UNKNOWN { + stage.Message = message + stage.Status = bean2.WORKFLOW_STAGE_STATUS_FAILED + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_NOT_STARTED { + stage.StartTime = time.Now().Format(bean3.LayoutRFC3339) + } + } + default: + impl.logger.Errorw("unknown pod status", "podStatus", podStatus, "message", message) + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_NOT_STARTED { + extractedStatus := adapter.ConvertStatusToDevtronStatus(wfStatus, "") + if extractedStatus.IsTerminal() { + stage.Status = extractedStatus + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + updatedPodStatus = wfStatus + } + } else { + stage.Message = message + stage.Status = bean2.WORKFLOW_STAGE_STATUS_UNKNOWN + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + } + } + } + } + return currentWorkflowStages, updatedPodStatus +} + +// Each case has 2 steps to do +// step-1: update latest status field if its not terminal already +// step-2: accordingly update stage status +func (impl *WorkFlowStageStatusServiceImpl) updateWorkflowStagesToDevtronStatus(currentWorkflowStages []*repository.WorkflowExecutionStage, wfStatus string, currentWfDBstatus, wfMessage string, podStatus string) ([]*repository.WorkflowExecutionStage, string) { + // implementation + updatedWfStatus := currentWfDBstatus + //todo for switch case use enums + switch strings.ToLower(podStatus) { + case strings.ToLower(string(v1alpha1.NodePending)): + updatedWfStatus = util.ComputeWorkflowStatus(currentWfDBstatus, wfStatus, cdWorkflow.WorkflowWaitingToStart) + + // update workflow preparation stage and pod status if terminal + for _, stage := range currentWorkflowStages { + if stage.StageName == bean2.WORKFLOW_PREPARATION && !stage.Status.IsTerminal() { + extractedStatus := adapter.ConvertStatusToDevtronStatus(wfStatus, wfMessage) + if extractedStatus != bean2.WORKFLOW_STAGE_STATUS_NOT_STARTED { + stage.Status = extractedStatus + } + } + + //also mark pod status as terminal if wfstatus is terminal + if stage.StageName == bean2.POD_EXECUTION && slices.Contains(cdWorkflow.WfrTerminalStatusList, wfStatus) { + stage.Status = adapter.ConvertStatusToDevtronStatus(wfStatus, wfMessage) + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + } + } + case strings.ToLower(string(v1alpha1.NodeRunning)): + updatedWfStatus = util.ComputeWorkflowStatus(currentWfDBstatus, wfStatus, constants.Running) + + //if pod is running, update preparation and execution stages + for _, stage := range currentWorkflowStages { + if stage.StatusFor == bean2.WORKFLOW_STAGE_STATUS_TYPE_WORKFLOW { + //mark preparation stage as completed + if stage.StageName == bean2.WORKFLOW_PREPARATION { + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_RUNNING { + stage.Status = bean2.WORKFLOW_STAGE_STATUS_SUCCEEDED + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + } + } + + //mark execution stage as started + if stage.StageName == bean2.WORKFLOW_EXECUTION { + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_NOT_STARTED { + stage.Status = bean2.WORKFLOW_STAGE_STATUS_RUNNING + stage.StartTime = time.Now().Format(bean3.LayoutRFC3339) + } else if stage.Status == bean2.WORKFLOW_STAGE_STATUS_RUNNING { + extractedStatus := adapter.ConvertStatusToDevtronStatus(wfStatus, wfMessage) + if extractedStatus.IsTerminal() { + stage.Status = extractedStatus + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + } + } + } + } + } + case strings.ToLower(string(v1alpha1.NodeSucceeded)): + updatedWfStatus = util.ComputeWorkflowStatus(currentWfDBstatus, wfStatus, cdWorkflow.WorkflowSucceeded) + + //if pod is succeeded, update execution stage + for _, stage := range currentWorkflowStages { + if stage.StatusFor == bean2.WORKFLOW_STAGE_STATUS_TYPE_WORKFLOW { + //mark execution stage as completed + if stage.StageName == bean2.WORKFLOW_EXECUTION { + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_RUNNING { + stage.Status = bean2.WORKFLOW_STAGE_STATUS_SUCCEEDED + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + } + } + } + } + case strings.ToLower(string(v1alpha1.NodeFailed)), strings.ToLower(string(v1alpha1.NodeError)): + updatedWfStatus = util.ComputeWorkflowStatus(currentWfDBstatus, wfStatus, cdWorkflow.WorkflowFailed) + + //if pod is failed, update execution stage + for _, stage := range currentWorkflowStages { + if stage.StatusFor == bean2.WORKFLOW_STAGE_STATUS_TYPE_WORKFLOW { + //mark execution stage as completed + if stage.StageName == bean2.WORKFLOW_EXECUTION { + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_RUNNING { + extractedStatus := adapter.ConvertStatusToDevtronStatus(wfStatus, wfMessage) + if extractedStatus.IsTerminal() { + stage.Status = extractedStatus + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + if extractedStatus == bean2.WORKFLOW_STAGE_STATUS_TIMEOUT { + updatedWfStatus = cdWorkflow.WorkflowTimedOut + } + if extractedStatus == bean2.WORKFLOW_STAGE_STATUS_ABORTED { + updatedWfStatus = cdWorkflow.WorkflowCancel + } + } + } + } else if stage.StageName == bean2.WORKFLOW_PREPARATION && !stage.Status.IsTerminal() { + extractedStatus := adapter.ConvertStatusToDevtronStatus(wfStatus, wfMessage) + if extractedStatus.IsTerminal() { + stage.Status = extractedStatus + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + if extractedStatus == bean2.WORKFLOW_STAGE_STATUS_TIMEOUT { + updatedWfStatus = cdWorkflow.WorkflowTimedOut + } + if extractedStatus == bean2.WORKFLOW_STAGE_STATUS_ABORTED { + updatedWfStatus = cdWorkflow.WorkflowCancel + } + } + } + } + } + default: + impl.logger.Errorw("unknown pod status", "podStatus", podStatus) + //mark workflow stage status as unknown + for _, stage := range currentWorkflowStages { + if stage.StatusFor == bean2.WORKFLOW_STAGE_STATUS_TYPE_WORKFLOW { + //mark execution stage as completed + if stage.StageName == bean2.WORKFLOW_EXECUTION { + if stage.Status == bean2.WORKFLOW_STAGE_STATUS_RUNNING { + stage.Status = bean2.WORKFLOW_STAGE_STATUS_UNKNOWN + updatedWfStatus = bean2.WORKFLOW_STAGE_STATUS_UNKNOWN.ToString() + } + } + if stage.StageName == bean2.WORKFLOW_PREPARATION && !stage.Status.IsTerminal() { + //assumption: once pod is running we don't internally do any extra operation which would call this function and simply update status accrording to kubewatch events + //that's why we are getting pod status as unknown because we don't explicity set pod status + //this is the case when our internal code has called to update status before actually scheduling pod + //update wf status as given in request, don't change that + updatedWfStatus = util.ComputeWorkflowStatus(currentWfDBstatus, wfStatus, "") + extractedStatus := adapter.ConvertStatusToDevtronStatus(wfStatus, wfMessage) + if extractedStatus.IsTerminal() { + stage.Status = extractedStatus + stage.EndTime = time.Now().Format(bean3.LayoutRFC3339) + if extractedStatus == bean2.WORKFLOW_STAGE_STATUS_TIMEOUT { + updatedWfStatus = cdWorkflow.WorkflowTimedOut + } + if extractedStatus == bean2.WORKFLOW_STAGE_STATUS_ABORTED { + updatedWfStatus = cdWorkflow.WorkflowCancel + } + } + } + } + + } + } + + return currentWorkflowStages, updatedWfStatus +} + +func (impl *WorkFlowStageStatusServiceImpl) GetWorkflowStagesByWorkflowIdsAndWfType(wfIds []int, wfType string) ([]*repository.WorkflowExecutionStage, error) { + // implementation + + dbData, err := impl.workflowStatusRepository.GetWorkflowStagesByWorkflowIdsAndWtype(wfIds, wfType) + if err != nil { + impl.logger.Errorw("error in getting ci workflow stages", "error", err) + return nil, err + } + if len(dbData) == 0 { + return []*repository.WorkflowExecutionStage{}, nil + } else { + return dbData, nil + } +} + +func (impl *WorkFlowStageStatusServiceImpl) GetWorkflowStagesByWorkflowIdAndType(wfId int, wfType string) ([]*repository.WorkflowExecutionStage, error) { + // implementation + + dbData, err := impl.workflowStatusRepository.GetWorkflowStagesByWorkflowIdAndWtype(wfId, wfType) + if err != nil { + impl.logger.Errorw("error in getting ci workflow stages", "error", err) + return nil, err + } + if len(dbData) == 0 { + return []*repository.WorkflowExecutionStage{}, nil + } else { + return dbData, nil + } +} + +func (impl *WorkFlowStageStatusServiceImpl) ConvertDBWorkflowStageToMap(workflowStages []*repository.WorkflowExecutionStage, wfId int, status, podStatus, message, wfType string, startTime, endTime time.Time) map[string][]*bean2.WorkflowStageDto { + wfMap := make(map[string][]*bean2.WorkflowStageDto) + foundInDb := false + if !impl.config.EnableWorkflowExecutionStage { + // if flag is not enabled then return empty map + return map[string][]*bean2.WorkflowStageDto{} + } + for _, wfStage := range workflowStages { + if wfStage.WorkflowId == wfId { + wfMap[wfStage.StatusFor.ToString()] = append(wfMap[wfStage.StatusFor.ToString()], adapter.ConvertDBWorkflowStageToDto(wfStage)) + foundInDb = true + } + } + + if !foundInDb { + //for old data where stages are not saved in db return empty map + return map[string][]*bean2.WorkflowStageDto{} + } + + return wfMap + +} + +func (impl *WorkFlowStageStatusServiceImpl) SaveWorkflowStages(wfId int, wfType, wfName string, tx *pg.Tx) error { + if impl.config.EnableWorkflowExecutionStage { + pipelineStageStatus := adapter.GetDefaultPipelineStatusForWorkflow(wfId, wfType) + pipelineStageStatus, err := impl.workflowStatusRepository.SaveWorkflowStages(pipelineStageStatus, tx) + if err != nil { + impl.logger.Errorw("error in saving workflow stages", "workflowName", wfName, "error", err) + return err + } + } else { + impl.logger.Debugw("workflow execution stage is disabled", "workflowName", wfName) + } + return nil +} + +func (impl *WorkFlowStageStatusServiceImpl) UpdateWorkflowStages(wfId int, wfType, wfName, wfStatus, podStatus, message, podName string, tx *pg.Tx) (string, string, error) { + if impl.config.EnableWorkflowExecutionStage { + pipelineStageStatus, updatedWfStatus, updatedPodStatus := impl.getUpdatedPipelineStagesForWorkflow(wfId, wfType, wfStatus, podStatus, message, podName) + pipelineStageStatus, err := impl.workflowStatusRepository.UpdateWorkflowStages(pipelineStageStatus, tx) + if err != nil { + impl.logger.Errorw("error in saving workflow stages", "workflowName", wfName, "error", err) + return wfStatus, podStatus, err + } + + return updatedWfStatus, updatedPodStatus, nil + } else { + impl.logger.Debugw("workflow execution stage is disabled", "workflowName", wfName) + } + return wfStatus, podStatus, nil +} diff --git a/pkg/pipeline/workflowStatus/adapter/adapter.go b/pkg/pipeline/workflowStatus/adapter/adapter.go new file mode 100644 index 0000000000..7d81975033 --- /dev/null +++ b/pkg/pipeline/workflowStatus/adapter/adapter.go @@ -0,0 +1,126 @@ +package adapter + +import ( + "encoding/json" + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" + "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" + bean3 "github.com/devtron-labs/devtron/pkg/bean" + "github.com/devtron-labs/devtron/pkg/pipeline/constants" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/bean" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/repository" + "github.com/devtron-labs/devtron/pkg/sql" + "log" + "strings" + "time" +) + +func ConvertDBWorkflowStageToDto(stage *repository.WorkflowExecutionStage) *bean.WorkflowStageDto { + if stage == nil { + return &bean.WorkflowStageDto{} + } + return &bean.WorkflowStageDto{ + Id: stage.Id, + StageName: stage.StageName, + Status: stage.Status, + Message: stage.Message, + Metadata: getMetadataJson(stage.Metadata), + WorkflowId: stage.WorkflowId, + WorkflowType: stage.WorkflowType, + StartTime: stage.StartTime, + EndTime: stage.EndTime, + } +} + +func getMetadataJson(metadata string) map[string]interface{} { + var response map[string]interface{} + //todo handle error + json.Unmarshal([]byte(metadata), &response) + //if err != nil { + // return nil, err + //} + return response +} + +// for workflow there can be other status map than for pod status like in aborted case +func ConvertStatusToDevtronStatus(wfStatus string, wfMessage string) bean.WorkflowStageStatus { + // implementation + switch strings.ToLower(wfStatus) { + case strings.ToLower(string(v1alpha1.NodePending)), strings.ToLower(cdWorkflow.WorkflowWaitingToStart): + return bean.WORKFLOW_STAGE_STATUS_NOT_STARTED + case strings.ToLower(cdWorkflow.WorkflowStarting), strings.ToLower(string(v1alpha1.NodeRunning)): + return bean.WORKFLOW_STAGE_STATUS_RUNNING + case strings.ToLower(cdWorkflow.WorkflowSucceeded): + return bean.WORKFLOW_STAGE_STATUS_SUCCEEDED + case strings.ToLower(cdWorkflow.WorkflowFailed), strings.ToLower(string(v1alpha1.NodeError)), "errored": + if strings.ToLower(wfMessage) == strings.ToLower(constants.POD_TIMEOUT_MESSAGE) { + return bean.WORKFLOW_STAGE_STATUS_TIMEOUT + } else { + return bean.WORKFLOW_STAGE_STATUS_FAILED + } + case strings.ToLower(cdWorkflow.WorkflowAborted), strings.ToLower(cdWorkflow.WorkflowCancel): + return bean.WORKFLOW_STAGE_STATUS_ABORTED + default: + log.Println("unknown wf status", "wf", wfStatus) + return bean.WORKFLOW_STAGE_STATUS_UNKNOWN + } +} + +func GetDefaultPipelineStatusForWorkflow(wfId int, wfType string) []*repository.WorkflowExecutionStage { + // implementation + resp := []*repository.WorkflowExecutionStage{} + resp = append(resp, GetDefaultWorkflowPreparationStage(wfId, wfType)) + resp = append(resp, GetDefaultWorkflowExecutionStage(wfId, wfType)) + resp = append(resp, GetDefaultPodExecutionStage(wfId, wfType)) + return resp +} + +func GetDefaultWorkflowPreparationStage(workflowId int, workflowType string) *repository.WorkflowExecutionStage { + // implementation + return &repository.WorkflowExecutionStage{ + StageName: bean.WORKFLOW_PREPARATION, + Status: bean.WORKFLOW_STAGE_STATUS_RUNNING, + StatusFor: bean.WORKFLOW_STAGE_STATUS_TYPE_WORKFLOW, + StartTime: time.Now().Format(bean3.LayoutRFC3339), + WorkflowId: workflowId, + WorkflowType: workflowType, + Message: "", + Metadata: "{}", + EndTime: "", + //todo do we need audit log since ci-workflow also doesn't have it ?? + AuditLog: sql.NewDefaultAuditLog(1), + } +} + +func GetDefaultWorkflowExecutionStage(workflowId int, workflowType string) *repository.WorkflowExecutionStage { + // implementation + return &repository.WorkflowExecutionStage{ + StageName: bean.WORKFLOW_EXECUTION, + Status: bean.WORKFLOW_STAGE_STATUS_NOT_STARTED, + StatusFor: bean.WORKFLOW_STAGE_STATUS_TYPE_WORKFLOW, + StartTime: "", + WorkflowId: workflowId, + WorkflowType: workflowType, + Message: "", + Metadata: "{}", + EndTime: "", + //todo do we need audit log since ci-workflow also doesn't have it ?? + AuditLog: sql.NewDefaultAuditLog(1), + } +} + +func GetDefaultPodExecutionStage(workflowId int, workflowType string) *repository.WorkflowExecutionStage { + // implementation + return &repository.WorkflowExecutionStage{ + StageName: bean.POD_EXECUTION, + Status: bean.WORKFLOW_STAGE_STATUS_NOT_STARTED, + StatusFor: bean.WORKFLOW_STAGE_STATUS_TYPE_POD, + StartTime: "", + WorkflowId: workflowId, + WorkflowType: workflowType, + Message: "", + Metadata: "{}", + EndTime: "", + //todo do we need audit log since ci-workflow also doesn't have it ?? + AuditLog: sql.NewDefaultAuditLog(1), + } +} diff --git a/pkg/pipeline/workflowStatus/bean/bean.go b/pkg/pipeline/workflowStatus/bean/bean.go new file mode 100644 index 0000000000..f1bd26a22c --- /dev/null +++ b/pkg/pipeline/workflowStatus/bean/bean.go @@ -0,0 +1,62 @@ +package bean + +type WorkflowStageName string + +const ( + WORKFLOW_PREPARATION WorkflowStageName = "Preparation" + WORKFLOW_EXECUTION WorkflowStageName = "Execution" + POD_EXECUTION WorkflowStageName = "Execution" +) + +func (n WorkflowStageName) ToString() string { + return string(n) +} + +type WorkflowStageStatusFor string + +const ( + WORKFLOW_STAGE_STATUS_TYPE_WORKFLOW WorkflowStageStatusFor = "workflow" + WORKFLOW_STAGE_STATUS_TYPE_POD WorkflowStageStatusFor = "pod" +) + +func (n WorkflowStageStatusFor) ToString() string { + return string(n) +} + +type WorkflowStageStatus string + +const ( + WORKFLOW_STAGE_STATUS_NOT_STARTED WorkflowStageStatus = "NOT_STARTED" + WORKFLOW_STAGE_STATUS_UNKNOWN WorkflowStageStatus = "UNKNOWN" + WORKFLOW_STAGE_STATUS_RUNNING WorkflowStageStatus = "RUNNING" + WORKFLOW_STAGE_STATUS_SUCCEEDED WorkflowStageStatus = "SUCCEEDED" + WORKFLOW_STAGE_STATUS_FAILED WorkflowStageStatus = "FAILED" + WORKFLOW_STAGE_STATUS_ABORTED WorkflowStageStatus = "ABORTED" + WORKFLOW_STAGE_STATUS_TIMEOUT WorkflowStageStatus = "TIMEOUT" + //don't forget to add new status in IsTerminal() method if it is terminal status +) + +func (n WorkflowStageStatus) ToString() string { + return string(n) +} + +func (n WorkflowStageStatus) IsTerminal() bool { + switch n { + case WORKFLOW_STAGE_STATUS_SUCCEEDED, WORKFLOW_STAGE_STATUS_FAILED, WORKFLOW_STAGE_STATUS_ABORTED, WORKFLOW_STAGE_STATUS_TIMEOUT: + return true + default: + return false + } +} + +type WorkflowStageDto struct { + Id int `json:"id"` + StageName WorkflowStageName `json:"stageName"` + Status WorkflowStageStatus `json:"status"` + Message string `json:"message"` + Metadata map[string]interface{} `json:"metadata"` + WorkflowId int `json:"workflowId"` + WorkflowType string `json:"workflowType"` + StartTime string `json:"startTime"` + EndTime string `json:"endTime"` +} diff --git a/pkg/pipeline/workflowStatus/repository/WorkflowStageRepository.go b/pkg/pipeline/workflowStatus/repository/WorkflowStageRepository.go new file mode 100644 index 0000000000..d384f30c3b --- /dev/null +++ b/pkg/pipeline/workflowStatus/repository/WorkflowStageRepository.go @@ -0,0 +1,94 @@ +package repository + +import ( + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/bean" + "github.com/devtron-labs/devtron/pkg/sql" + "github.com/go-pg/pg" + "go.uber.org/zap" +) + +type WorkflowStageRepository interface { + SaveWorkflowStages(workflowStage []*WorkflowExecutionStage, tx *pg.Tx) ([]*WorkflowExecutionStage, error) + UpdateWorkflowStages(workflowStage []*WorkflowExecutionStage, tx *pg.Tx) ([]*WorkflowExecutionStage, error) + GetWorkflowStagesByWorkflowIdAndType(workflowId int, workflowType string) ([]*WorkflowExecutionStage, error) + GetWorkflowStagesByWorkflowIdAndWtype(wfId int, wfType string) ([]*WorkflowExecutionStage, error) + GetWorkflowStagesByWorkflowIdsAndWtype(wfIds []int, wfType string) ([]*WorkflowExecutionStage, error) +} + +type WorkflowStageRepositoryImpl struct { + logger *zap.SugaredLogger + dbConnection *pg.DB +} + +type WorkflowExecutionStage struct { + tableName struct{} `sql:"workflow_execution_stage" pg:",discard_unknown_columns"` + Id int `sql:"id,pk"` + StageName bean.WorkflowStageName `sql:"stage_name,notnull"` // same as app name + Status bean.WorkflowStageStatus `sql:"status"` + StatusFor bean.WorkflowStageStatusFor `sql:"status_for"` + Message string `sql:"message"` + Metadata string `sql:"metadata"` + WorkflowId int `sql:"workflow_id,notnull"` + WorkflowType string `sql:"workflow_type,notnull"` + StartTime string `sql:"start_time"` + EndTime string `sql:"end_time"` + + sql.AuditLog +} + +func NewWorkflowStageRepositoryImpl(logger *zap.SugaredLogger, + dbConnection *pg.DB) *WorkflowStageRepositoryImpl { + return &WorkflowStageRepositoryImpl{ + logger: logger, + dbConnection: dbConnection, + } +} + +func (impl *WorkflowStageRepositoryImpl) SaveWorkflowStages(workflowStages []*WorkflowExecutionStage, tx *pg.Tx) ([]*WorkflowExecutionStage, error) { + err := tx.Insert(&workflowStages) + return workflowStages, err +} + +func (impl *WorkflowStageRepositoryImpl) UpdateWorkflowStages(workflowStages []*WorkflowExecutionStage, tx *pg.Tx) ([]*WorkflowExecutionStage, error) { + if len(workflowStages) == 0 { + return workflowStages, nil + } + //todo optimise below for bulk update + for _, stage := range workflowStages { + _, err := tx.Model(stage).WherePK().Update() + if err != nil { + return workflowStages, err + } + } + //_, err := .WherePK().UpdateNotNull() + return workflowStages, nil +} + +func (impl *WorkflowStageRepositoryImpl) GetWorkflowStagesByWorkflowIdAndType(workflowId int, workflowType string) ([]*WorkflowExecutionStage, error) { + var workflowStages []*WorkflowExecutionStage + err := impl.dbConnection.Model(&workflowStages).Where("workflow_id = ?", workflowId).Where("workflow_type = ?", workflowType).Order("id ASC").Select() + return workflowStages, err +} + +func (impl *WorkflowStageRepositoryImpl) GetWorkflowStagesByWorkflowIdAndWtype(wfId int, wfType string) ([]*WorkflowExecutionStage, error) { + var workflowStages []*WorkflowExecutionStage + err := impl.dbConnection.Model(&workflowStages).Where("workflow_id = ?", wfId).Where("workflow_type = ?", wfType).Order("id ASC").Select() + if err != nil { + impl.logger.Errorw("error in fetching ci workflow stages", "err", err) + return workflowStages, err + } + return workflowStages, err +} + +func (impl *WorkflowStageRepositoryImpl) GetWorkflowStagesByWorkflowIdsAndWtype(wfIds []int, wfType string) ([]*WorkflowExecutionStage, error) { + var workflowStages []*WorkflowExecutionStage + if len(wfIds) == 0 { + return []*WorkflowExecutionStage{}, nil + } + err := impl.dbConnection.Model(&workflowStages).Where("workflow_id in (?)", pg.In(wfIds)).Where("workflow_type = ?", wfType).Order("id ASC").Select() + if err != nil { + impl.logger.Errorw("error in fetching ci workflow stages", "err", err) + return workflowStages, err + } + return workflowStages, err +} diff --git a/pkg/pipeline/workflowStatus/util/util.go b/pkg/pipeline/workflowStatus/util/util.go new file mode 100644 index 0000000000..ab347ad277 --- /dev/null +++ b/pkg/pipeline/workflowStatus/util/util.go @@ -0,0 +1,18 @@ +package util + +import ( + "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" + "slices" +) + +func ComputeWorkflowStatus(currentWfDBstatus, wfStatus, stageStatus string) string { + updatedWfStatus := currentWfDBstatus + if !slices.Contains(cdWorkflow.WfrTerminalStatusList, currentWfDBstatus) { + if len(stageStatus) > 0 && !slices.Contains(cdWorkflow.WfrTerminalStatusList, wfStatus) { + updatedWfStatus = stageStatus + } else { + updatedWfStatus = wfStatus + } + } + return updatedWfStatus +} diff --git a/pkg/workflow/cd/CdWorkflowCommonService.go b/pkg/workflow/cd/CdWorkflowCommonService.go index f84b891125..d1c5314244 100644 --- a/pkg/workflow/cd/CdWorkflowCommonService.go +++ b/pkg/workflow/cd/CdWorkflowCommonService.go @@ -58,6 +58,7 @@ type CdWorkflowCommonServiceImpl struct { pipelineRepository pipelineConfig.PipelineRepository pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository deploymentConfigService common2.DeploymentConfigService + cdWorkflowRunnerService CdWorkflowRunnerService } func NewCdWorkflowCommonServiceImpl(logger *zap.SugaredLogger, @@ -65,7 +66,8 @@ func NewCdWorkflowCommonServiceImpl(logger *zap.SugaredLogger, pipelineStatusTimelineService status.PipelineStatusTimelineService, pipelineRepository pipelineConfig.PipelineRepository, pipelineStatusTimelineRepository pipelineConfig.PipelineStatusTimelineRepository, - deploymentConfigService common2.DeploymentConfigService) (*CdWorkflowCommonServiceImpl, error) { + deploymentConfigService common2.DeploymentConfigService, + cdWorkflowRunnerService CdWorkflowRunnerService) (*CdWorkflowCommonServiceImpl, error) { config, err := types.GetCdConfig() if err != nil { return nil, err @@ -78,6 +80,7 @@ func NewCdWorkflowCommonServiceImpl(logger *zap.SugaredLogger, pipelineRepository: pipelineRepository, pipelineStatusTimelineRepository: pipelineStatusTimelineRepository, deploymentConfigService: deploymentConfigService, + cdWorkflowRunnerService: cdWorkflowRunnerService, }, nil } @@ -171,7 +174,7 @@ func (impl *CdWorkflowCommonServiceImpl) MarkCurrentDeploymentFailed(runner *pip runner.Message = util.GetClientErrorDetailedMessage(releaseErr) runner.FinishedOn = time.Now() runner.UpdateAuditLog(triggeredBy) - err1 := impl.cdWorkflowRepository.UpdateWorkFlowRunner(runner) + err1 := impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(runner) if err1 != nil { impl.logger.Errorw("error updating cd wf runner status", "err", releaseErr, "currentRunner", runner) return err1 @@ -223,7 +226,7 @@ func (impl *CdWorkflowCommonServiceImpl) UpdateNonTerminalStatusInRunner(ctx con } cdWfr.Status = status cdWfr.UpdateAuditLog(userId) - err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(cdWfr) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(cdWfr) if err != nil { impl.logger.Errorw("error on update cd workflow runner, UpdateNonTerminalStatusInRunner", "cdWfr", cdWfr, "err", err) return err diff --git a/pkg/workflow/cd/CdWorkflowRunnerService.go b/pkg/workflow/cd/CdWorkflowRunnerService.go index 511d694bc4..8883817251 100644 --- a/pkg/workflow/cd/CdWorkflowRunnerService.go +++ b/pkg/workflow/cd/CdWorkflowRunnerService.go @@ -17,35 +17,59 @@ package cd import ( + bean2 "github.com/devtron-labs/devtron/api/bean" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow" + "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig/bean/workflow/cdWorkflow" + bean4 "github.com/devtron-labs/devtron/pkg/pipeline/bean" + "github.com/devtron-labs/devtron/pkg/pipeline/types" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus" + bean3 "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/bean" + "github.com/devtron-labs/devtron/pkg/sql" "github.com/devtron-labs/devtron/pkg/workflow/cd/adapter" "github.com/devtron-labs/devtron/pkg/workflow/cd/bean" + "github.com/devtron-labs/devtron/util" "go.uber.org/zap" ) type CdWorkflowRunnerService interface { UpdateWfr(dto *bean.CdWorkflowRunnerDto, updatedBy int) error UpdateIsArtifactUploaded(wfrId int, isArtifactUploaded bool) error + SaveCDWorkflowRunnerWithStage(wfr *pipelineConfig.CdWorkflowRunner) (*pipelineConfig.CdWorkflowRunner, error) + UpdateCdWorkflowRunnerWithStage(wfr *pipelineConfig.CdWorkflowRunner) error + GetPrePostWorkflowStagesByWorkflowRunnerIdsList(wfIdWfTypeMap map[int]bean4.CdWorkflowWithArtifact) (map[int]map[string][]*bean3.WorkflowStageDto, error) } type CdWorkflowRunnerServiceImpl struct { logger *zap.SugaredLogger cdWorkflowRepository pipelineConfig.CdWorkflowRepository + workflowStageService workflowStatus.WorkFlowStageStatusService + transactionManager sql.TransactionWrapper + config *types.CiConfig } func NewCdWorkflowRunnerServiceImpl(logger *zap.SugaredLogger, - cdWorkflowRepository pipelineConfig.CdWorkflowRepository) *CdWorkflowRunnerServiceImpl { - return &CdWorkflowRunnerServiceImpl{ + cdWorkflowRepository pipelineConfig.CdWorkflowRepository, + workflowStageService workflowStatus.WorkFlowStageStatusService, + transactionManager sql.TransactionWrapper) *CdWorkflowRunnerServiceImpl { + impl := &CdWorkflowRunnerServiceImpl{ logger: logger, cdWorkflowRepository: cdWorkflowRepository, + workflowStageService: workflowStageService, + transactionManager: transactionManager, } + ciConfig, err := types.GetCiConfig() + if err != nil { + return nil + } + impl.config = ciConfig + return impl } func (impl *CdWorkflowRunnerServiceImpl) UpdateWfr(dto *bean.CdWorkflowRunnerDto, updatedBy int) error { runnerDbObj := adapter.ConvertCdWorkflowRunnerDtoToDbObj(dto) runnerDbObj.UpdateAuditLog(int32(updatedBy)) - err := impl.cdWorkflowRepository.UpdateWorkFlowRunner(runnerDbObj) + err := impl.UpdateCdWorkflowRunnerWithStage(runnerDbObj) if err != nil { impl.logger.Errorw("error in updating runner status in db", "runnerId", runnerDbObj.Id, "err", err) return err @@ -61,3 +85,116 @@ func (impl *CdWorkflowRunnerServiceImpl) UpdateIsArtifactUploaded(wfrId int, isA } return nil } + +func (impl *CdWorkflowRunnerServiceImpl) SaveCDWorkflowRunnerWithStage(wfr *pipelineConfig.CdWorkflowRunner) (*pipelineConfig.CdWorkflowRunner, error) { + // implementation + tx, err := impl.transactionManager.StartTx() + if err != nil { + impl.logger.Errorw("error in starting transaction to save default configurations", "workflowName", wfr.Name, "error", err) + return wfr, err + } + + defer func() { + dbErr := impl.transactionManager.RollbackTx(tx) + if dbErr != nil && dbErr.Error() != util.SqlAlreadyCommitedErrMsg { + impl.logger.Errorw("error in rolling back transaction", "workflowName", wfr.Name, "error", dbErr) + } + }() + if impl.config.EnableWorkflowExecutionStage { + wfr.Status = cdWorkflow.WorkflowWaitingToStart + } + wfr, err = impl.cdWorkflowRepository.SaveWorkFlowRunnerWithTx(wfr, tx) + if err != nil { + impl.logger.Errorw("error in saving workflow", "payload", wfr, "error", err) + return wfr, err + } + + err = impl.workflowStageService.SaveWorkflowStages(wfr.Id, wfr.WorkflowType.String(), wfr.Name, tx) + if err != nil { + impl.logger.Errorw("error in saving workflow stages", "workflowName", wfr.Name, "error", err) + return wfr, err + } + + err = impl.transactionManager.CommitTx(tx) + if err != nil { + impl.logger.Errorw("error in committing transaction", "workflowName", wfr.Name, "error", err) + return wfr, err + } + return wfr, nil +} + +func (impl *CdWorkflowRunnerServiceImpl) UpdateCdWorkflowRunnerWithStage(wfr *pipelineConfig.CdWorkflowRunner) error { + // implementation + tx, err := impl.transactionManager.StartTx() + if err != nil { + impl.logger.Errorw("error in starting transaction to save default configurations", "workflowName", wfr.Name, "error", err) + return err + } + + defer func() { + dbErr := impl.transactionManager.RollbackTx(tx) + if dbErr != nil && dbErr.Error() != util.SqlAlreadyCommitedErrMsg { + impl.logger.Errorw("error in rolling back transaction", "workflowName", wfr.Name, "error", dbErr) + } + }() + if wfr.WorkflowType == bean2.CD_WORKFLOW_TYPE_PRE || wfr.WorkflowType == bean2.CD_WORKFLOW_TYPE_POST { + wfr.Status, wfr.PodStatus, err = impl.workflowStageService.UpdateWorkflowStages(wfr.Id, wfr.WorkflowType.String(), wfr.Name, wfr.Status, wfr.PodStatus, wfr.Message, wfr.PodName, tx) + if err != nil { + impl.logger.Errorw("error in updating workflow stages", "workflowName", wfr.Name, "error", err) + return err + } + } + + //update workflow runner now with updatedWfStatus if applicable + err = impl.cdWorkflowRepository.UpdateWorkFlowRunnerWithTx(wfr, tx) + if err != nil { + impl.logger.Errorw("error in saving workflow", "payload", wfr, "error", err) + return err + } + + err = impl.transactionManager.CommitTx(tx) + if err != nil { + impl.logger.Errorw("error in committing transaction", "workflowName", wfr.Name, "error", err) + return err + } + return nil + +} + +func (impl *CdWorkflowRunnerServiceImpl) GetPrePostWorkflowStagesByWorkflowRunnerIdsList(wfIdWfTypeMap map[int]bean4.CdWorkflowWithArtifact) (map[int]map[string][]*bean3.WorkflowStageDto, error) { + // implementation + resp := map[int]map[string][]*bean3.WorkflowStageDto{} + if len(wfIdWfTypeMap) == 0 { + return resp, nil + } + //first create a map of pre-runner ids and post-runner ids + prePostRunnerIds := map[string][]int{} + for wfId, wf := range wfIdWfTypeMap { + if wf.WorkflowType == bean2.CD_WORKFLOW_TYPE_PRE.String() { + prePostRunnerIds[bean2.CD_WORKFLOW_TYPE_PRE.String()] = append(prePostRunnerIds[bean2.CD_WORKFLOW_TYPE_PRE.String()], wfId) + } else if wf.WorkflowType == bean2.CD_WORKFLOW_TYPE_POST.String() { + prePostRunnerIds[bean2.CD_WORKFLOW_TYPE_POST.String()] = append(prePostRunnerIds[bean2.CD_WORKFLOW_TYPE_POST.String()], wfId) + } + } + + preCdDbData, err := impl.workflowStageService.GetWorkflowStagesByWorkflowIdsAndWfType(prePostRunnerIds[bean2.CD_WORKFLOW_TYPE_PRE.String()], bean2.CD_WORKFLOW_TYPE_PRE.String()) + if err != nil { + impl.logger.Errorw("error in getting pre-ci workflow stages", "error", err) + return resp, err + } + //do the above for post cd + postCdDbData, err := impl.workflowStageService.GetWorkflowStagesByWorkflowIdsAndWfType(prePostRunnerIds[bean2.CD_WORKFLOW_TYPE_POST.String()], bean2.CD_WORKFLOW_TYPE_POST.String()) + if err != nil { + impl.logger.Errorw("error in getting post-ci workflow stages", "error", err) + return resp, err + } + //iterate over prePostRunnerIds and create response structure using ConvertDBWorkflowStageToMap function + for wfId, wf := range wfIdWfTypeMap { + if wf.WorkflowType == bean2.CD_WORKFLOW_TYPE_PRE.String() { + resp[wfId] = impl.workflowStageService.ConvertDBWorkflowStageToMap(preCdDbData, wfId, wf.Status, wf.PodStatus, wf.Message, wf.WorkflowType, wf.StartedOn, wf.FinishedOn) + } else if wf.WorkflowType == bean2.CD_WORKFLOW_TYPE_POST.String() { + resp[wfId] = impl.workflowStageService.ConvertDBWorkflowStageToMap(postCdDbData, wfId, wf.Status, wf.PodStatus, wf.Message, wf.WorkflowType, wf.StartedOn, wf.FinishedOn) + } + } + return resp, nil +} diff --git a/pkg/workflow/dag/WorkflowDagExecutor.go b/pkg/workflow/dag/WorkflowDagExecutor.go index cfd6236c34..2cddf7a65c 100644 --- a/pkg/workflow/dag/WorkflowDagExecutor.go +++ b/pkg/workflow/dag/WorkflowDagExecutor.go @@ -46,7 +46,6 @@ import ( eventProcessorBean "github.com/devtron-labs/devtron/pkg/eventProcessor/bean" "github.com/devtron-labs/devtron/pkg/pipeline" constants2 "github.com/devtron-labs/devtron/pkg/pipeline/constants" - "github.com/devtron-labs/devtron/pkg/pipeline/executors" repository2 "github.com/devtron-labs/devtron/pkg/plugin/repository" "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning" repository3 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" @@ -119,6 +118,8 @@ type WorkflowDagExecutorImpl struct { eventFactory client.EventFactory customTagService pipeline.CustomTagService pipelineStatusTimelineService status.PipelineStatusTimelineService + cdWorkflowRunnerService cd.CdWorkflowRunnerService + ciService pipeline.CiService helmAppService client2.HelmAppService @@ -148,6 +149,8 @@ func NewWorkflowDagExecutorImpl(Logger *zap.SugaredLogger, pipelineRepository pi eventFactory client.EventFactory, customTagService pipeline.CustomTagService, pipelineStatusTimelineService status.PipelineStatusTimelineService, + cdWorkflowRunnerService cd.CdWorkflowRunnerService, + ciService pipeline.CiService, helmAppService client2.HelmAppService, cdWorkflowCommonService cd.CdWorkflowCommonService, cdTriggerService devtronApps.TriggerService, @@ -184,6 +187,8 @@ func NewWorkflowDagExecutorImpl(Logger *zap.SugaredLogger, pipelineRepository pi asyncRunnable: asyncRunnable, scanHistoryRepository: scanHistoryRepository, imageScanService: imageScanService, + cdWorkflowRunnerService: cdWorkflowRunnerService, + ciService: ciService, } config, err := types.GetCdConfig() if err != nil { @@ -332,7 +337,7 @@ func (impl *WorkflowDagExecutorImpl) handleAsyncTriggerReleaseError(ctx context. } cdWfr.UpdatedBy = 1 cdWfr.UpdatedOn = time.Now() - err := impl.cdWorkflowRepository.UpdateWorkFlowRunner(cdWfr) + err := impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(cdWfr) if err != nil { impl.logger.Errorw("error on update cd workflow runner", "wfr", cdWfr, "err", err) return @@ -742,13 +747,13 @@ func (impl *WorkflowDagExecutorImpl) UpdateCiWorkflowForCiSuccess(request *bean2 return err } // if workflow already cancelled then return, this state arises when user force aborts a ci - if savedWorkflow.Status == executors.WorkflowCancel { + if savedWorkflow.Status == cdWorkflow2.WorkflowCancel { return err } savedWorkflow.Status = string(v1alpha1.NodeSucceeded) savedWorkflow.IsArtifactUploaded = workflow.GetArtifactUploadedType(request.IsArtifactUploaded) impl.logger.Debugw("updating workflow ", "savedWorkflow", savedWorkflow) - err = impl.ciWorkflowRepository.UpdateWorkFlow(savedWorkflow) + err = impl.ciService.UpdateCiWorkflowWithStage(savedWorkflow) if err != nil { impl.logger.Errorw("update wf failed for id ", "err", err) return err diff --git a/pkg/workflow/status/WorkflowStatusService.go b/pkg/workflow/status/WorkflowStatusService.go index e889a9c1a2..7ca800d796 100644 --- a/pkg/workflow/status/WorkflowStatusService.go +++ b/pkg/workflow/status/WorkflowStatusService.go @@ -40,6 +40,7 @@ import ( "github.com/devtron-labs/devtron/pkg/eventProcessor/out" "github.com/devtron-labs/devtron/pkg/pipeline/types" "github.com/devtron-labs/devtron/pkg/sql" + "github.com/devtron-labs/devtron/pkg/workflow/cd" "github.com/devtron-labs/devtron/pkg/workflow/dag" util3 "github.com/devtron-labs/devtron/util" "github.com/go-pg/pg" @@ -86,6 +87,7 @@ type WorkflowStatusServiceImpl struct { pipelineRepository pipelineConfig.PipelineRepository appListingService app.AppListingService deploymentConfigService common2.DeploymentConfigService + cdWorkflowRunnerService cd.CdWorkflowRunnerService } func NewWorkflowStatusServiceImpl(logger *zap.SugaredLogger, @@ -107,6 +109,7 @@ func NewWorkflowStatusServiceImpl(logger *zap.SugaredLogger, pipelineRepository pipelineConfig.PipelineRepository, appListingService app.AppListingService, deploymentConfigService common2.DeploymentConfigService, + cdWorkflowRunnerService cd.CdWorkflowRunnerService, ) (*WorkflowStatusServiceImpl, error) { impl := &WorkflowStatusServiceImpl{ logger: logger, @@ -130,6 +133,7 @@ func NewWorkflowStatusServiceImpl(logger *zap.SugaredLogger, pipelineRepository: pipelineRepository, appListingService: appListingService, deploymentConfigService: deploymentConfigService, + cdWorkflowRunnerService: cdWorkflowRunnerService, } config, err := types.GetCdConfig() if err != nil { @@ -169,7 +173,7 @@ func (impl *WorkflowStatusServiceImpl) CheckHelmAppStatusPeriodicallyAndUpdateIn return err } } - err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(wfr) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(wfr) if err != nil { impl.logger.Errorw("error on update cd workflow runner", "wfr", wfr, "err", err) return err @@ -237,7 +241,7 @@ func (impl *WorkflowStatusServiceImpl) UpdatePipelineTimelineAndStatusByLiveAppl cdWfr.Status = cdWorkflow2.WorkflowUnableToFetchState cdWfr.UpdatedOn = time.Now() cdWfr.UpdatedBy = 1 - err = impl.cdWorkflowRepository.UpdateWorkFlowRunner(&cdWfr) + err = impl.cdWorkflowRunnerService.UpdateCdWorkflowRunnerWithStage(&cdWfr) if err != nil { impl.logger.Errorw("error on update cd workflow runner", "cdWfr", cdWfr, "err", err) return err, isTimelineUpdated diff --git a/scripts/sql/31902900_operation_audit.down.sql b/scripts/sql/31902900_operation_audit.down.sql new file mode 100644 index 0000000000..9088fbe9d8 --- /dev/null +++ b/scripts/sql/31902900_operation_audit.down.sql @@ -0,0 +1,5 @@ +-- Drop Table: operation_audit +DROP TABLE IF EXISTS "public"."operation_audit"; + +-- Drop Sequence: id_seq_operation_audit +DROP SEQUENCE IF EXISTS id_seq_operation_audit; \ No newline at end of file diff --git a/scripts/sql/31902900_operation_audit.up.sql b/scripts/sql/31902900_operation_audit.up.sql new file mode 100644 index 0000000000..05d1744d8f --- /dev/null +++ b/scripts/sql/31902900_operation_audit.up.sql @@ -0,0 +1,21 @@ +BEGIN; + +-- Create Sequence for operation_audit +CREATE SEQUENCE IF NOT EXISTS id_seq_operation_audit; + +-- Table Definition: operation_audit +CREATE TABLE IF NOT EXISTS "public"."operation_audit" ( + "id" int NOT NULL DEFAULT nextval('id_seq_operation_audit'::regclass), + "entity_id" int NOT NULL, + "entity_type" VARCHAR(50) NOT NULL , + "operation_type" VARCHAR(20) NOT NULL, + "entity_value_json" jsonb NOT NULL, + "entity_value_schema_type" VARCHAR(20) NOT NULL, + "created_on" timestamptz NOT NULL, + "created_by" int4 NOT NULL, + "updated_on" timestamptz NOT NULL, + "updated_by" int4 NOT NULL, + PRIMARY KEY ("id") + ); + +COMMIT; \ No newline at end of file diff --git a/scripts/sql/32002900_build_worker_status.down.sql b/scripts/sql/32002900_build_worker_status.down.sql new file mode 100644 index 0000000000..6dc8e268d5 --- /dev/null +++ b/scripts/sql/32002900_build_worker_status.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS public.workflow_execution_stage CASCADE; +DROP SEQUENCE IF EXISTS id_seq_workflow_execution_stage; \ No newline at end of file diff --git a/scripts/sql/32002900_build_worker_status.up.sql b/scripts/sql/32002900_build_worker_status.up.sql new file mode 100644 index 0000000000..2a43914bb7 --- /dev/null +++ b/scripts/sql/32002900_build_worker_status.up.sql @@ -0,0 +1,20 @@ +CREATE SEQUENCE IF NOT EXISTS id_seq_workflow_execution_stage; + +CREATE TABLE IF NOT EXISTS public.workflow_execution_stage ( + id int4 NOT NULL DEFAULT nextval('id_seq_workflow_execution_stage'::regclass), + stage_name varchar(50) NULL, + step_name varchar(50) NULL, + status varchar(50) NULL, + status_for varchar(50) NULL, + message text NULL, + metadata text NULL, + workflow_id int4 NOT NULL, + workflow_type varchar(50) NOT NULL, + start_time text, + end_time text, + created_on timestamptz NOT NULL, + created_by int4 NOT NULL, + updated_on timestamptz NOT NULL, + updated_by int4 NOT null, + PRIMARY KEY ("id") +); \ No newline at end of file diff --git a/specs/workflow/workflow-stage-status.internal.yaml b/specs/workflow/workflow-stage-status.internal.yaml new file mode 100644 index 0000000000..549951a0f9 --- /dev/null +++ b/specs/workflow/workflow-stage-status.internal.yaml @@ -0,0 +1,97 @@ +openapi: 3.0.0 +info: + title: Workflow Status API for showing execution stage + version: 1.0.0 +paths: + /workflow/status: #this is not real API, only for sharing purpose + get: + summary: Get Workflow Status + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/GetWorkflowStatusResponse' + example: '{"status":"In progress","startTime":"1","endTime":"","message":"e-message","podStatus":"Running","podName":"pod-name","workflowExecutionStages":{"workflow":[{"stageName":"Preparation","status":"SUCCESS","startTime":"1","endTime":"2","message":"p-message","metadata":{}},{"stageName":"Execution","status":"STARTED","startTime":"2","endTime":"","message":"e-message","metadata":{}}],"pod":[{"stageName":"Execution","status":"STARTED","startTime":"2","endTime":"","message":"e-message","metadata":{"ClusterID":"?? (possible?)","podName":"pod-name"}}]}}' + +components: + schemas: + GetWorkflowStatusResponse: + type: object + properties: + status: + type: string + description: Workflow current status - for backward compatibility + startTime: + type: string + format: date-time + description: Workflow start time + endTime: + type: string + format: date-time + description: Workflow end time + message: + type: string + description: Workflow message + podStatus: + type: string + description: Pod status + podName: + type: string + description: Pod name + workflowExecutionStages: + $ref: '#/components/schemas/WorkflowStages' + + WorkflowStages: + type: object + properties: + workflow: + type: array + items: + type: object + properties: + stageName: + type: string + description: Preparation/Execution + status: + type: string + enum: [NOT_STARTED, RUNNING, SUCCEEDED, FAILED, ABORTED, TIMEOUT, UNKNOWN] + startTime: + type: string + format: date-time + endTime: + type: string + format: date-time + message: + type: string + metadata: + type: object + pod: + type: array + items: + type: object + properties: + stageName: + type: string + description: Execution + status: + type: string + enum: [NOT_STARTED, RUNNING, SUCCEEDED, FAILED, ABORTED, TIMEOUT, UNKNOWN] + startTime: + type: string + format: date-time + endTime: + type: string + format: date-time + message: + type: string + metadata: + type: object + properties: + ClusterID: + type: string + description: Cluster ID + podName: + type: string + description: Pod name \ No newline at end of file diff --git a/util/CommonConstant.go b/util/CommonConstant.go index f643d1d725..fcf2c6fd6a 100644 --- a/util/CommonConstant.go +++ b/util/CommonConstant.go @@ -30,4 +30,5 @@ const ( ConfigMapSecretUsageTypeVolume string = "volume" YamlSeparator string = "---\n" NotSupportedErr = "This feature is not supported" + SqlAlreadyCommitedErrMsg = "sql: transaction has already been committed or rolled back" ) diff --git a/vendor/github.com/devtron-labs/common-lib/utils/k8s/K8sUtil.go b/vendor/github.com/devtron-labs/common-lib/utils/k8s/K8sUtil.go index f3adf4a535..3854eb5eb9 100644 --- a/vendor/github.com/devtron-labs/common-lib/utils/k8s/K8sUtil.go +++ b/vendor/github.com/devtron-labs/common-lib/utils/k8s/K8sUtil.go @@ -144,6 +144,7 @@ type K8sService interface { //below functions are exposed for K8sUtilExtended GetRestConfigByClusterWithoutCustomTransport(clusterConfig *ClusterConfig) (*rest.Config, error) OverrideRestConfigWithCustomTransport(restConfig *rest.Config) (*rest.Config, error) + CreateNsWithLabels(namespace string, labels map[string]string, client *v12.CoreV1Client) (ns *v1.Namespace, err error) CreateNs(namespace string, client *v12.CoreV1Client) (ns *v1.Namespace, err error) } @@ -299,12 +300,12 @@ func (impl *K8sServiceImpl) CreateNsIfNotExists(namespace string, clusterConfig } ns, exists, err := impl.GetNsIfExists(namespace, v12Client) if err != nil { - impl.logger.Errorw("error", "error", err, "clusterConfig", clusterConfig) + impl.logger.Errorw("error", "error", err) return ns, false, err } if exists { nsCreated = false - impl.logger.Infow("namesapce already exist") + impl.logger.Infow("namespace already exist", "namespace", namespace) return ns, nsCreated, nil } impl.logger.Infow("ns not exists creating", "ns", namespace) @@ -359,6 +360,17 @@ func (impl *K8sServiceImpl) CreateNs(namespace string, client *v12.CoreV1Client) } } +func (impl *K8sServiceImpl) CreateNsWithLabels(namespace string, labels map[string]string, client *v12.CoreV1Client) (ns *v1.Namespace, err error) { + nsSpec := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace, Labels: labels}} + ns, err = client.Namespaces().Create(context.Background(), nsSpec, metav1.CreateOptions{}) + if err != nil { + impl.logger.Errorw("error in creating ns", "err", err) + return nil, err + } else { + return ns, nil + } +} + func (impl *K8sServiceImpl) deleteNs(namespace string, client *v12.CoreV1Client) error { err := client.Namespaces().Delete(context.Background(), namespace, metav1.DeleteOptions{}) return err diff --git a/vendor/modules.txt b/vendor/modules.txt index aa07298980..7ce8e9e49e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -336,7 +336,7 @@ github.com/davecgh/go-spew/spew # github.com/deckarep/golang-set v1.8.0 ## explicit; go 1.17 github.com/deckarep/golang-set -# github.com/devtron-labs/authenticator v0.4.35-0.20240809073103-6e11da8083f8 => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2 +# github.com/devtron-labs/authenticator v0.4.35-0.20240809073103-6e11da8083f8 => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250213074742-042aeadc9d72 ## explicit; go 1.21 github.com/devtron-labs/authenticator/apiToken github.com/devtron-labs/authenticator/client @@ -344,7 +344,7 @@ github.com/devtron-labs/authenticator/jwt github.com/devtron-labs/authenticator/middleware github.com/devtron-labs/authenticator/oidc github.com/devtron-labs/authenticator/password -# github.com/devtron-labs/common-lib v0.18.1-0.20241001061923-eda545dc839e => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2 +# github.com/devtron-labs/common-lib v0.18.1-0.20241001061923-eda545dc839e => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250213074742-042aeadc9d72 ## explicit; go 1.21 github.com/devtron-labs/common-lib/async github.com/devtron-labs/common-lib/blob-storage @@ -2215,8 +2215,8 @@ xorm.io/xorm/log xorm.io/xorm/names xorm.io/xorm/schemas xorm.io/xorm/tags -# github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250130075053-69cdda98e3e2 -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250130075053-69cdda98e3e2 +# github.com/devtron-labs/authenticator => github.com/devtron-labs/devtron-services/authenticator v0.0.0-20250213074742-042aeadc9d72 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250213074742-042aeadc9d72 # github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 # github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.5.5 # k8s.io/api => k8s.io/api v0.29.7 diff --git a/wire_gen.go b/wire_gen.go index b59e017b53..8141c31139 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -99,7 +99,7 @@ import ( "github.com/devtron-labs/devtron/internal/sql/repository/deploymentConfig" repository9 "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry" "github.com/devtron-labs/devtron/internal/sql/repository/helper" - repository21 "github.com/devtron-labs/devtron/internal/sql/repository/imageTagging" + repository22 "github.com/devtron-labs/devtron/internal/sql/repository/imageTagging" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/sql/repository/resourceGroup" "github.com/devtron-labs/devtron/internal/util" @@ -111,7 +111,7 @@ import ( "github.com/devtron-labs/devtron/pkg/appClone/batch" appStatus2 "github.com/devtron-labs/devtron/pkg/appStatus" "github.com/devtron-labs/devtron/pkg/appStore/chartGroup" - repository27 "github.com/devtron-labs/devtron/pkg/appStore/chartGroup/repository" + repository28 "github.com/devtron-labs/devtron/pkg/appStore/chartGroup/repository" "github.com/devtron-labs/devtron/pkg/appStore/chartProvider" "github.com/devtron-labs/devtron/pkg/appStore/discover/repository" service6 "github.com/devtron-labs/devtron/pkg/appStore/discover/service" @@ -143,14 +143,14 @@ import ( read12 "github.com/devtron-labs/devtron/pkg/build/artifacts/imageTagging/read" "github.com/devtron-labs/devtron/pkg/build/git/gitHost" read16 "github.com/devtron-labs/devtron/pkg/build/git/gitHost/read" - repository25 "github.com/devtron-labs/devtron/pkg/build/git/gitHost/repository" + repository26 "github.com/devtron-labs/devtron/pkg/build/git/gitHost/repository" read11 "github.com/devtron-labs/devtron/pkg/build/git/gitMaterial/read" - repository19 "github.com/devtron-labs/devtron/pkg/build/git/gitMaterial/repository" + repository20 "github.com/devtron-labs/devtron/pkg/build/git/gitMaterial/repository" "github.com/devtron-labs/devtron/pkg/build/git/gitProvider" read6 "github.com/devtron-labs/devtron/pkg/build/git/gitProvider/read" repository11 "github.com/devtron-labs/devtron/pkg/build/git/gitProvider/repository" "github.com/devtron-labs/devtron/pkg/build/git/gitWebhook" - repository22 "github.com/devtron-labs/devtron/pkg/build/git/gitWebhook/repository" + repository23 "github.com/devtron-labs/devtron/pkg/build/git/gitWebhook/repository" pipeline2 "github.com/devtron-labs/devtron/pkg/build/pipeline" read10 "github.com/devtron-labs/devtron/pkg/build/pipeline/read" "github.com/devtron-labs/devtron/pkg/bulkAction" @@ -187,7 +187,7 @@ import ( "github.com/devtron-labs/devtron/pkg/deployment/manifest/publish" "github.com/devtron-labs/devtron/pkg/deployment/providerConfig" "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps" - repository24 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/userDeploymentRequest/repository" + repository25 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/userDeploymentRequest/repository" service3 "github.com/devtron-labs/devtron/pkg/deployment/trigger/devtronApps/userDeploymentRequest/service" "github.com/devtron-labs/devtron/pkg/deploymentGroup" "github.com/devtron-labs/devtron/pkg/devtronResource" @@ -216,7 +216,7 @@ import ( "github.com/devtron-labs/devtron/pkg/k8s/capacity" "github.com/devtron-labs/devtron/pkg/k8s/informer" "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs" - repository26 "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs/repository" + repository27 "github.com/devtron-labs/devtron/pkg/kubernetesResourceAuditLogs/repository" "github.com/devtron-labs/devtron/pkg/module" "github.com/devtron-labs/devtron/pkg/module/repo" "github.com/devtron-labs/devtron/pkg/module/store" @@ -224,17 +224,19 @@ import ( "github.com/devtron-labs/devtron/pkg/pipeline" "github.com/devtron-labs/devtron/pkg/pipeline/executors" "github.com/devtron-labs/devtron/pkg/pipeline/history" - repository20 "github.com/devtron-labs/devtron/pkg/pipeline/history/repository" + repository21 "github.com/devtron-labs/devtron/pkg/pipeline/history/repository" "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders" "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/ci" "github.com/devtron-labs/devtron/pkg/pipeline/infraProviders/infraGetters/job" - repository17 "github.com/devtron-labs/devtron/pkg/pipeline/repository" + repository18 "github.com/devtron-labs/devtron/pkg/pipeline/repository" "github.com/devtron-labs/devtron/pkg/pipeline/types" + "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus" + repository17 "github.com/devtron-labs/devtron/pkg/pipeline/workflowStatus/repository" "github.com/devtron-labs/devtron/pkg/plugin" - repository18 "github.com/devtron-labs/devtron/pkg/plugin/repository" + repository19 "github.com/devtron-labs/devtron/pkg/plugin/repository" "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning" read13 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/read" - repository23 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" + repository24 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/imageScanning/repository" "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool" repository15 "github.com/devtron-labs/devtron/pkg/policyGovernance/security/scanTool/repository" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" @@ -585,7 +587,10 @@ func InitializeApp() (*App, error) { envLevelAppMetricsRepositoryImpl := repository16.NewEnvLevelAppMetricsRepositoryImpl(db, sugaredLogger) deployedAppMetricsServiceImpl := deployedAppMetrics.NewDeployedAppMetricsServiceImpl(sugaredLogger, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, chartRefServiceImpl) appListingServiceImpl := app2.NewAppListingServiceImpl(sugaredLogger, appListingRepositoryImpl, appRepositoryImpl, appListingViewBuilderImpl, pipelineRepositoryImpl, linkoutsRepositoryImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, environmentRepositoryImpl, chartRepositoryImpl, ciPipelineRepositoryImpl, dockerRegistryIpsConfigServiceImpl, userRepositoryImpl, deployedAppMetricsServiceImpl, ciArtifactRepositoryImpl, envConfigOverrideReadServiceImpl, ciPipelineConfigReadServiceImpl) - appServiceImpl := app2.NewAppService(pipelineOverrideRepositoryImpl, utilMergeUtil, sugaredLogger, pipelineRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, appRepositoryImpl, configMapRepositoryImpl, chartRepositoryImpl, cdWorkflowRepositoryImpl, commonServiceImpl, chartTemplateServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceConfig, appStatusServiceImpl, installedAppReadServiceImpl, installedAppVersionHistoryRepositoryImpl, scopedVariableCMCSManagerImpl, acdConfig, gitOpsConfigReadServiceImpl, gitOperationServiceImpl, deploymentTemplateServiceImpl, appListingServiceImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) + workflowStageRepositoryImpl := repository17.NewWorkflowStageRepositoryImpl(sugaredLogger, db) + workFlowStageStatusServiceImpl := workflowStatus.NewWorkflowStageFlowStatusServiceImpl(sugaredLogger, workflowStageRepositoryImpl, ciWorkflowRepositoryImpl, cdWorkflowRepositoryImpl, transactionUtilImpl) + cdWorkflowRunnerServiceImpl := cd.NewCdWorkflowRunnerServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl, workFlowStageStatusServiceImpl, transactionUtilImpl) + appServiceImpl := app2.NewAppService(pipelineOverrideRepositoryImpl, utilMergeUtil, sugaredLogger, pipelineRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, appRepositoryImpl, configMapRepositoryImpl, chartRepositoryImpl, cdWorkflowRepositoryImpl, commonServiceImpl, chartTemplateServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceConfig, appStatusServiceImpl, installedAppReadServiceImpl, installedAppVersionHistoryRepositoryImpl, scopedVariableCMCSManagerImpl, acdConfig, gitOpsConfigReadServiceImpl, gitOperationServiceImpl, deploymentTemplateServiceImpl, appListingServiceImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl, cdWorkflowRunnerServiceImpl) scopedVariableManagerImpl, err := variables.NewScopedVariableManagerImpl(sugaredLogger, scopedVariableServiceImpl, variableEntityMappingServiceImpl, variableSnapshotHistoryServiceImpl, variableTemplateParserImpl) if err != nil { return nil, err @@ -601,8 +606,8 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - pipelineStageRepositoryImpl := repository17.NewPipelineStageRepository(sugaredLogger, db) - globalPluginRepositoryImpl := repository18.NewGlobalPluginRepository(sugaredLogger, db) + pipelineStageRepositoryImpl := repository18.NewPipelineStageRepository(sugaredLogger, db) + globalPluginRepositoryImpl := repository19.NewGlobalPluginRepository(sugaredLogger, db) globalPluginServiceImpl := plugin.NewGlobalPluginService(sugaredLogger, globalPluginRepositoryImpl, pipelineStageRepositoryImpl, userServiceImpl) pipelineStageServiceImpl := pipeline.NewPipelineStageService(sugaredLogger, pipelineStageRepositoryImpl, globalPluginRepositoryImpl, pipelineRepositoryImpl, scopedVariableManagerImpl, globalPluginServiceImpl) ciTemplateRepositoryImpl := pipelineConfig.NewCiTemplateRepositoryImpl(db, sugaredLogger) @@ -613,7 +618,7 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - materialRepositoryImpl := repository19.NewMaterialRepositoryImpl(db) + materialRepositoryImpl := repository20.NewMaterialRepositoryImpl(db) gitMaterialReadServiceImpl := read11.NewGitMaterialReadServiceImpl(sugaredLogger, materialRepositoryImpl) appCrudOperationServiceImpl := app2.NewAppCrudOperationServiceImpl(appLabelRepositoryImpl, sugaredLogger, appRepositoryImpl, userRepositoryImpl, installedAppRepositoryImpl, genericNoteServiceImpl, installedAppDBServiceImpl, crudOperationServiceConfig, dbMigrationServiceImpl, gitMaterialReadServiceImpl) imageTagRepositoryImpl := repository2.NewImageTagRepository(db, sugaredLogger) @@ -627,24 +632,24 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - prePostCdScriptHistoryRepositoryImpl := repository20.NewPrePostCdScriptHistoryRepositoryImpl(sugaredLogger, db) - configMapHistoryRepositoryImpl := repository20.NewConfigMapHistoryRepositoryImpl(sugaredLogger, db, transactionUtilImpl) + prePostCdScriptHistoryRepositoryImpl := repository21.NewPrePostCdScriptHistoryRepositoryImpl(sugaredLogger, db) + configMapHistoryRepositoryImpl := repository21.NewConfigMapHistoryRepositoryImpl(sugaredLogger, db, transactionUtilImpl) configMapHistoryServiceImpl := configMapAndSecret.NewConfigMapHistoryServiceImpl(sugaredLogger, configMapHistoryRepositoryImpl, pipelineRepositoryImpl, configMapRepositoryImpl, userServiceImpl, scopedVariableCMCSManagerImpl) prePostCdScriptHistoryServiceImpl := history.NewPrePostCdScriptHistoryServiceImpl(sugaredLogger, prePostCdScriptHistoryRepositoryImpl, configMapRepositoryImpl, configMapHistoryServiceImpl) - gitMaterialHistoryRepositoryImpl := repository20.NewGitMaterialHistoryRepositoyImpl(db) + gitMaterialHistoryRepositoryImpl := repository21.NewGitMaterialHistoryRepositoyImpl(db) gitMaterialHistoryServiceImpl := history.NewGitMaterialHistoryServiceImpl(gitMaterialHistoryRepositoryImpl, sugaredLogger) - ciPipelineHistoryRepositoryImpl := repository20.NewCiPipelineHistoryRepositoryImpl(db, sugaredLogger) + ciPipelineHistoryRepositoryImpl := repository21.NewCiPipelineHistoryRepositoryImpl(db, sugaredLogger) ciPipelineHistoryServiceImpl := history.NewCiPipelineHistoryServiceImpl(ciPipelineHistoryRepositoryImpl, sugaredLogger, ciPipelineRepositoryImpl) ciBuildConfigRepositoryImpl := pipelineConfig.NewCiBuildConfigRepositoryImpl(db, sugaredLogger) ciBuildConfigServiceImpl := pipeline.NewCiBuildConfigServiceImpl(sugaredLogger, ciBuildConfigRepositoryImpl) ciTemplateServiceImpl := pipeline.NewCiTemplateServiceImpl(sugaredLogger, ciBuildConfigServiceImpl, ciTemplateRepositoryImpl, ciTemplateOverrideRepositoryImpl) pipelineConfigRepositoryImpl := chartConfig.NewPipelineConfigRepository(db) configMapServiceImpl := pipeline.NewConfigMapServiceImpl(chartRepositoryImpl, sugaredLogger, chartRepoRepositoryImpl, mergeUtil, pipelineConfigRepositoryImpl, configMapRepositoryImpl, envConfigOverrideRepositoryImpl, commonServiceImpl, appRepositoryImpl, configMapHistoryServiceImpl, environmentRepositoryImpl, scopedVariableCMCSManagerImpl) - deploymentTemplateHistoryRepositoryImpl := repository20.NewDeploymentTemplateHistoryRepositoryImpl(sugaredLogger, db) + deploymentTemplateHistoryRepositoryImpl := repository21.NewDeploymentTemplateHistoryRepositoryImpl(sugaredLogger, db) deploymentTemplateHistoryServiceImpl := deploymentTemplate.NewDeploymentTemplateHistoryServiceImpl(sugaredLogger, deploymentTemplateHistoryRepositoryImpl, pipelineRepositoryImpl, chartRepositoryImpl, userServiceImpl, cdWorkflowRepositoryImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, chartRefServiceImpl) chartServiceImpl := chart.NewChartServiceImpl(chartRepositoryImpl, sugaredLogger, chartTemplateServiceImpl, chartRepoRepositoryImpl, appRepositoryImpl, mergeUtil, envConfigOverrideRepositoryImpl, pipelineConfigRepositoryImpl, environmentRepositoryImpl, deploymentTemplateHistoryServiceImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, chartRefServiceImpl, gitOpsConfigReadServiceImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) ciCdPipelineOrchestratorImpl := pipeline.NewCiCdPipelineOrchestrator(appRepositoryImpl, sugaredLogger, materialRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, ciPipelineMaterialRepositoryImpl, cdWorkflowRepositoryImpl, clientImpl, ciCdConfig, appWorkflowRepositoryImpl, environmentRepositoryImpl, attributesServiceImpl, appCrudOperationServiceImpl, userAuthServiceImpl, prePostCdScriptHistoryServiceImpl, pipelineStageServiceImpl, gitMaterialHistoryServiceImpl, ciPipelineHistoryServiceImpl, ciTemplateReadServiceImpl, ciTemplateServiceImpl, dockerArtifactStoreRepositoryImpl, ciArtifactRepositoryImpl, configMapServiceImpl, customTagServiceImpl, genericNoteServiceImpl, chartServiceImpl, transactionUtilImpl, gitOpsConfigReadServiceImpl, deploymentConfigServiceImpl) - ciServiceImpl := pipeline.NewCiServiceImpl(sugaredLogger, workflowServiceImpl, ciPipelineMaterialRepositoryImpl, ciWorkflowRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, ciPipelineRepositoryImpl, ciArtifactRepositoryImpl, pipelineStageServiceImpl, userServiceImpl, ciTemplateReadServiceImpl, appCrudOperationServiceImpl, environmentRepositoryImpl, appRepositoryImpl, scopedVariableManagerImpl, customTagServiceImpl, pluginInputVariableParserImpl, globalPluginServiceImpl, infraProviderImpl, ciCdPipelineOrchestratorImpl, attributesServiceImpl) + ciServiceImpl := pipeline.NewCiServiceImpl(sugaredLogger, workflowServiceImpl, ciPipelineMaterialRepositoryImpl, workFlowStageStatusServiceImpl, eventRESTClientImpl, eventSimpleFactoryImpl, ciPipelineRepositoryImpl, ciArtifactRepositoryImpl, pipelineStageServiceImpl, userServiceImpl, ciTemplateReadServiceImpl, appCrudOperationServiceImpl, environmentRepositoryImpl, appRepositoryImpl, scopedVariableManagerImpl, customTagServiceImpl, pluginInputVariableParserImpl, globalPluginServiceImpl, infraProviderImpl, ciCdPipelineOrchestratorImpl, attributesServiceImpl, ciWorkflowRepositoryImpl, transactionUtilImpl) ciLogServiceImpl, err := pipeline.NewCiLogServiceImpl(sugaredLogger, ciServiceImpl, k8sServiceImpl) if err != nil { return nil, err @@ -652,28 +657,28 @@ func InitializeApp() (*App, error) { resourceGroupRepositoryImpl := resourceGroup.NewResourceGroupRepositoryImpl(db) resourceGroupMappingRepositoryImpl := resourceGroup.NewResourceGroupMappingRepositoryImpl(db) resourceGroupServiceImpl := resourceGroup2.NewResourceGroupServiceImpl(sugaredLogger, resourceGroupRepositoryImpl, resourceGroupMappingRepositoryImpl, enforcerUtilImpl, devtronResourceSearchableKeyServiceImpl, appStatusRepositoryImpl) - imageTaggingRepositoryImpl := repository21.NewImageTaggingRepositoryImpl(db, transactionUtilImpl) + imageTaggingRepositoryImpl := repository22.NewImageTaggingRepositoryImpl(db, transactionUtilImpl) imageTaggingReadServiceImpl, err := read12.NewImageTaggingReadServiceImpl(imageTaggingRepositoryImpl, sugaredLogger) if err != nil { return nil, err } imageTaggingServiceImpl := imageTagging.NewImageTaggingServiceImpl(imageTaggingRepositoryImpl, imageTaggingReadServiceImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, sugaredLogger) blobStorageConfigServiceImpl := pipeline.NewBlobStorageConfigServiceImpl(sugaredLogger, k8sServiceImpl, ciCdConfig) - ciHandlerImpl := pipeline.NewCiHandlerImpl(sugaredLogger, ciServiceImpl, ciPipelineMaterialRepositoryImpl, clientImpl, ciWorkflowRepositoryImpl, workflowServiceImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, userServiceImpl, eventRESTClientImpl, eventSimpleFactoryImpl, ciPipelineRepositoryImpl, appListingRepositoryImpl, k8sServiceImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, environmentRepositoryImpl, imageTaggingServiceImpl, k8sCommonServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl, appWorkflowRepositoryImpl, customTagServiceImpl, environmentServiceImpl) - gitWebhookRepositoryImpl := repository22.NewGitWebhookRepositoryImpl(db) + ciHandlerImpl := pipeline.NewCiHandlerImpl(sugaredLogger, ciServiceImpl, ciPipelineMaterialRepositoryImpl, clientImpl, ciWorkflowRepositoryImpl, workflowServiceImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, userServiceImpl, eventRESTClientImpl, eventSimpleFactoryImpl, ciPipelineRepositoryImpl, appListingRepositoryImpl, k8sServiceImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, environmentRepositoryImpl, imageTaggingServiceImpl, k8sCommonServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl, appWorkflowRepositoryImpl, customTagServiceImpl, environmentServiceImpl, workFlowStageStatusServiceImpl) + gitWebhookRepositoryImpl := repository23.NewGitWebhookRepositoryImpl(db) gitWebhookServiceImpl := gitWebhook.NewGitWebhookServiceImpl(sugaredLogger, ciHandlerImpl, gitWebhookRepositoryImpl) gitWebhookRestHandlerImpl := restHandler.NewGitWebhookRestHandlerImpl(sugaredLogger, gitWebhookServiceImpl) ecrConfig, err := pipeline.GetEcrConfig() if err != nil { return nil, err } - ciTemplateHistoryRepositoryImpl := repository20.NewCiTemplateHistoryRepositoryImpl(db, sugaredLogger) + ciTemplateHistoryRepositoryImpl := repository21.NewCiTemplateHistoryRepositoryImpl(db, sugaredLogger) ciTemplateHistoryServiceImpl := history.NewCiTemplateHistoryServiceImpl(ciTemplateHistoryRepositoryImpl, sugaredLogger) buildPipelineSwitchServiceImpl := pipeline.NewBuildPipelineSwitchServiceImpl(sugaredLogger, ciPipelineConfigReadServiceImpl, ciPipelineRepositoryImpl, ciCdPipelineOrchestratorImpl, pipelineRepositoryImpl, ciWorkflowRepositoryImpl, appWorkflowRepositoryImpl, ciPipelineHistoryServiceImpl, ciTemplateOverrideRepositoryImpl, ciPipelineMaterialRepositoryImpl) ciPipelineConfigServiceImpl := pipeline.NewCiPipelineConfigServiceImpl(sugaredLogger, ciCdPipelineOrchestratorImpl, dockerArtifactStoreRepositoryImpl, gitMaterialReadServiceImpl, appRepositoryImpl, pipelineRepositoryImpl, ciPipelineConfigReadServiceImpl, ciPipelineRepositoryImpl, ecrConfig, appWorkflowRepositoryImpl, ciCdConfig, attributesServiceImpl, pipelineStageServiceImpl, ciPipelineMaterialRepositoryImpl, ciTemplateServiceImpl, ciTemplateReadServiceImpl, ciTemplateOverrideRepositoryImpl, ciTemplateHistoryServiceImpl, enforcerUtilImpl, ciWorkflowRepositoryImpl, resourceGroupServiceImpl, customTagServiceImpl, cdWorkflowRepositoryImpl, buildPipelineSwitchServiceImpl, pipelineStageRepositoryImpl, globalPluginRepositoryImpl) ciMaterialConfigServiceImpl := pipeline.NewCiMaterialConfigServiceImpl(sugaredLogger, materialRepositoryImpl, ciTemplateReadServiceImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, gitMaterialHistoryServiceImpl, pipelineRepositoryImpl, ciPipelineMaterialRepositoryImpl, transactionUtilImpl, gitMaterialReadServiceImpl) deploymentGroupRepositoryImpl := repository2.NewDeploymentGroupRepositoryImpl(sugaredLogger, db) - pipelineStrategyHistoryRepositoryImpl := repository20.NewPipelineStrategyHistoryRepositoryImpl(sugaredLogger, db) + pipelineStrategyHistoryRepositoryImpl := repository21.NewPipelineStrategyHistoryRepositoryImpl(sugaredLogger, db) pipelineStrategyHistoryServiceImpl := history.NewPipelineStrategyHistoryServiceImpl(sugaredLogger, pipelineStrategyHistoryRepositoryImpl, userServiceImpl) propertiesConfigServiceImpl := pipeline.NewPropertiesConfigServiceImpl(sugaredLogger, envConfigOverrideRepositoryImpl, chartRepositoryImpl, environmentRepositoryImpl, deploymentTemplateHistoryServiceImpl, scopedVariableManagerImpl, deployedAppMetricsServiceImpl, envConfigOverrideReadServiceImpl) imageDigestPolicyServiceImpl := imageDigestPolicy.NewImageDigestPolicyServiceImpl(sugaredLogger, qualifierMappingServiceImpl, devtronResourceSearchableKeyServiceImpl) @@ -684,7 +689,7 @@ func InitializeApp() (*App, error) { devtronAppCMCSServiceImpl := pipeline.NewDevtronAppCMCSServiceImpl(sugaredLogger, appServiceImpl, attributesRepositoryImpl) globalStrategyMetadataChartRefMappingRepositoryImpl := chartRepoRepository.NewGlobalStrategyMetadataChartRefMappingRepositoryImpl(db, sugaredLogger) devtronAppStrategyServiceImpl := pipeline.NewDevtronAppStrategyServiceImpl(sugaredLogger, chartRepositoryImpl, globalStrategyMetadataChartRefMappingRepositoryImpl, ciCdPipelineOrchestratorImpl, cdPipelineConfigServiceImpl) - cdWorkflowCommonServiceImpl, err := cd.NewCdWorkflowCommonServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl, pipelineStatusTimelineServiceImpl, pipelineRepositoryImpl, pipelineStatusTimelineRepositoryImpl, deploymentConfigServiceImpl) + cdWorkflowCommonServiceImpl, err := cd.NewCdWorkflowCommonServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl, pipelineStatusTimelineServiceImpl, pipelineRepositoryImpl, pipelineStatusTimelineRepositoryImpl, deploymentConfigServiceImpl, cdWorkflowRunnerServiceImpl) if err != nil { return nil, err } @@ -704,7 +709,7 @@ func InitializeApp() (*App, error) { installedAppDBExtendedServiceImpl := FullMode.NewInstalledAppDBExtendedServiceImpl(installedAppDBServiceImpl, appStatusServiceImpl, gitOpsConfigReadServiceImpl) gitOpsValidationServiceImpl := validation.NewGitOpsValidationServiceImpl(sugaredLogger, gitFactory, gitOperationServiceImpl, gitOpsConfigReadServiceImpl, chartTemplateServiceImpl, chartServiceImpl, installedAppDBExtendedServiceImpl) devtronAppGitOpConfigServiceImpl := gitOpsConfig.NewDevtronAppGitOpConfigServiceImpl(sugaredLogger, chartRepositoryImpl, chartServiceImpl, gitOpsConfigReadServiceImpl, gitOpsValidationServiceImpl, argoClientWrapperServiceImpl, deploymentConfigServiceImpl) - cdHandlerImpl := pipeline.NewCdHandlerImpl(sugaredLogger, userServiceImpl, cdWorkflowRepositoryImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, ciPipelineMaterialRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, ciWorkflowRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, imageTaggingServiceImpl, k8sServiceImpl, workflowServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl, customTagServiceImpl, deploymentConfigServiceImpl) + cdHandlerImpl := pipeline.NewCdHandlerImpl(sugaredLogger, userServiceImpl, cdWorkflowRepositoryImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, ciPipelineMaterialRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, ciWorkflowRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, imageTaggingServiceImpl, k8sServiceImpl, workflowServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl, customTagServiceImpl, deploymentConfigServiceImpl, workFlowStageStatusServiceImpl, cdWorkflowRunnerServiceImpl) appWorkflowServiceImpl := appWorkflow2.NewAppWorkflowServiceImpl(sugaredLogger, appWorkflowRepositoryImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, appRepositoryImpl, userAuthServiceImpl, chartServiceImpl, deploymentConfigServiceImpl) appCloneServiceImpl := appClone.NewAppCloneServiceImpl(sugaredLogger, pipelineBuilderImpl, attributesServiceImpl, chartServiceImpl, configMapServiceImpl, appWorkflowServiceImpl, appListingServiceImpl, propertiesConfigServiceImpl, pipelineStageServiceImpl, ciTemplateReadServiceImpl, appRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, ciPipelineConfigServiceImpl, gitOpsConfigReadServiceImpl) deploymentTemplateRepositoryImpl := repository2.NewDeploymentTemplateRepositoryImpl(db, sugaredLogger) @@ -713,13 +718,13 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - cvePolicyRepositoryImpl := repository23.NewPolicyRepositoryImpl(db, sugaredLogger) - imageScanResultRepositoryImpl := repository23.NewImageScanResultRepositoryImpl(db, sugaredLogger) - imageScanDeployInfoRepositoryImpl := repository23.NewImageScanDeployInfoRepositoryImpl(db, sugaredLogger) - imageScanObjectMetaRepositoryImpl := repository23.NewImageScanObjectMetaRepositoryImpl(db, sugaredLogger) - imageScanHistoryRepositoryImpl := repository23.NewImageScanHistoryRepositoryImpl(db, sugaredLogger) + cvePolicyRepositoryImpl := repository24.NewPolicyRepositoryImpl(db, sugaredLogger) + imageScanResultRepositoryImpl := repository24.NewImageScanResultRepositoryImpl(db, sugaredLogger) + imageScanDeployInfoRepositoryImpl := repository24.NewImageScanDeployInfoRepositoryImpl(db, sugaredLogger) + imageScanObjectMetaRepositoryImpl := repository24.NewImageScanObjectMetaRepositoryImpl(db, sugaredLogger) + imageScanHistoryRepositoryImpl := repository24.NewImageScanHistoryRepositoryImpl(db, sugaredLogger) imageScanHistoryReadServiceImpl := read13.NewImageScanHistoryReadService(sugaredLogger, imageScanHistoryRepositoryImpl) - cveStoreRepositoryImpl := repository23.NewCveStoreRepositoryImpl(db, sugaredLogger) + cveStoreRepositoryImpl := repository24.NewCveStoreRepositoryImpl(db, sugaredLogger) policyServiceImpl := imageScanning.NewPolicyServiceImpl(environmentServiceImpl, sugaredLogger, appRepositoryImpl, pipelineOverrideRepositoryImpl, cvePolicyRepositoryImpl, clusterServiceImplExtended, pipelineRepositoryImpl, imageScanResultRepositoryImpl, imageScanDeployInfoRepositoryImpl, imageScanObjectMetaRepositoryImpl, httpClient, ciArtifactRepositoryImpl, ciCdConfig, imageScanHistoryReadServiceImpl, cveStoreRepositoryImpl, ciTemplateRepositoryImpl, clusterReadServiceImpl, transactionUtilImpl) imageScanResultReadServiceImpl := read13.NewImageScanResultReadServiceImpl(sugaredLogger, imageScanResultRepositoryImpl) pipelineConfigRestHandlerImpl := configure.NewPipelineRestHandlerImpl(pipelineBuilderImpl, sugaredLogger, deploymentTemplateValidationServiceImpl, chartServiceImpl, devtronAppGitOpConfigServiceImpl, propertiesConfigServiceImpl, userServiceImpl, teamServiceImpl, enforcerImpl, ciHandlerImpl, validate, clientImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, dockerRegistryConfigImpl, cdHandlerImpl, appCloneServiceImpl, generateManifestDeploymentTemplateServiceImpl, appWorkflowServiceImpl, gitMaterialReadServiceImpl, policyServiceImpl, imageScanResultReadServiceImpl, ciPipelineMaterialRepositoryImpl, imageTaggingReadServiceImpl, imageTaggingServiceImpl, ciArtifactRepositoryImpl, deployedAppMetricsServiceImpl, chartRefServiceImpl, ciCdPipelineOrchestratorImpl, gitProviderReadServiceImpl, teamReadServiceImpl) @@ -728,20 +733,20 @@ func InitializeApp() (*App, error) { manifestCreationServiceImpl := manifest.NewManifestCreationServiceImpl(sugaredLogger, dockerRegistryIpsConfigServiceImpl, chartRefServiceImpl, scopedVariableCMCSManagerImpl, k8sCommonServiceImpl, deployedAppMetricsServiceImpl, imageDigestPolicyServiceImpl, utilMergeUtil, appCrudOperationServiceImpl, deploymentTemplateServiceImpl, argoClientWrapperServiceImpl, configMapHistoryRepositoryImpl, configMapRepositoryImpl, chartRepositoryImpl, envConfigOverrideRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciArtifactRepositoryImpl, pipelineOverrideRepositoryImpl, pipelineStrategyHistoryRepositoryImpl, pipelineConfigRepositoryImpl, deploymentTemplateHistoryRepositoryImpl, deploymentConfigServiceImpl, envConfigOverrideReadServiceImpl) configMapHistoryReadServiceImpl := read14.NewConfigMapHistoryReadService(sugaredLogger, configMapHistoryRepositoryImpl, scopedVariableCMCSManagerImpl) deployedConfigurationHistoryServiceImpl := history.NewDeployedConfigurationHistoryServiceImpl(sugaredLogger, userServiceImpl, deploymentTemplateHistoryServiceImpl, pipelineStrategyHistoryServiceImpl, configMapHistoryServiceImpl, cdWorkflowRepositoryImpl, scopedVariableCMCSManagerImpl, deploymentTemplateHistoryReadServiceImpl, configMapHistoryReadServiceImpl) - userDeploymentRequestRepositoryImpl := repository24.NewUserDeploymentRequestRepositoryImpl(db, transactionUtilImpl) + userDeploymentRequestRepositoryImpl := repository25.NewUserDeploymentRequestRepositoryImpl(db, transactionUtilImpl) userDeploymentRequestServiceImpl := service3.NewUserDeploymentRequestServiceImpl(sugaredLogger, userDeploymentRequestRepositoryImpl) imageScanDeployInfoReadServiceImpl := read13.NewImageScanDeployInfoReadService(sugaredLogger, imageScanDeployInfoRepositoryImpl) imageScanDeployInfoServiceImpl := imageScanning.NewImageScanDeployInfoService(sugaredLogger, imageScanDeployInfoRepositoryImpl) - manifestPushConfigRepositoryImpl := repository17.NewManifestPushConfigRepository(sugaredLogger, db) - scanToolExecutionHistoryMappingRepositoryImpl := repository23.NewScanToolExecutionHistoryMappingRepositoryImpl(db, sugaredLogger) + manifestPushConfigRepositoryImpl := repository18.NewManifestPushConfigRepository(sugaredLogger, db) + scanToolExecutionHistoryMappingRepositoryImpl := repository24.NewScanToolExecutionHistoryMappingRepositoryImpl(db, sugaredLogger) cdWorkflowReadServiceImpl := read15.NewCdWorkflowReadServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) imageScanServiceImpl := imageScanning.NewImageScanServiceImpl(sugaredLogger, imageScanHistoryRepositoryImpl, imageScanResultRepositoryImpl, imageScanObjectMetaRepositoryImpl, cveStoreRepositoryImpl, imageScanDeployInfoRepositoryImpl, userServiceImpl, appRepositoryImpl, environmentServiceImpl, ciArtifactRepositoryImpl, policyServiceImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, scanToolMetadataRepositoryImpl, scanToolExecutionHistoryMappingRepositoryImpl, cvePolicyRepositoryImpl, cdWorkflowReadServiceImpl) - triggerServiceImpl, err := devtronApps.NewTriggerServiceImpl(sugaredLogger, cdWorkflowCommonServiceImpl, gitOpsManifestPushServiceImpl, gitOpsConfigReadServiceImpl, argoK8sClientImpl, acdConfig, argoClientWrapperServiceImpl, pipelineStatusTimelineServiceImpl, chartTemplateServiceImpl, workflowEventPublishServiceImpl, manifestCreationServiceImpl, deployedConfigurationHistoryServiceImpl, pipelineStageServiceImpl, globalPluginServiceImpl, customTagServiceImpl, pluginInputVariableParserImpl, prePostCdScriptHistoryServiceImpl, scopedVariableCMCSManagerImpl, workflowServiceImpl, imageDigestPolicyServiceImpl, userServiceImpl, clientImpl, helmAppServiceImpl, enforcerUtilImpl, userDeploymentRequestServiceImpl, helmAppClientImpl, eventSimpleFactoryImpl, eventRESTClientImpl, environmentVariables, appRepositoryImpl, ciPipelineMaterialRepositoryImpl, imageScanHistoryReadServiceImpl, imageScanDeployInfoReadServiceImpl, imageScanDeployInfoServiceImpl, pipelineRepositoryImpl, pipelineOverrideRepositoryImpl, manifestPushConfigRepositoryImpl, chartRepositoryImpl, environmentRepositoryImpl, cdWorkflowRepositoryImpl, ciWorkflowRepositoryImpl, ciArtifactRepositoryImpl, ciTemplateReadServiceImpl, gitMaterialReadServiceImpl, appLabelRepositoryImpl, ciPipelineRepositoryImpl, appWorkflowRepositoryImpl, dockerArtifactStoreRepositoryImpl, imageScanServiceImpl, k8sServiceImpl, transactionUtilImpl, deploymentConfigServiceImpl, ciCdPipelineOrchestratorImpl, gitOperationServiceImpl, attributesServiceImpl, clusterRepositoryImpl) + triggerServiceImpl, err := devtronApps.NewTriggerServiceImpl(sugaredLogger, cdWorkflowCommonServiceImpl, gitOpsManifestPushServiceImpl, gitOpsConfigReadServiceImpl, argoK8sClientImpl, acdConfig, argoClientWrapperServiceImpl, pipelineStatusTimelineServiceImpl, chartTemplateServiceImpl, workflowEventPublishServiceImpl, manifestCreationServiceImpl, deployedConfigurationHistoryServiceImpl, pipelineStageServiceImpl, globalPluginServiceImpl, customTagServiceImpl, pluginInputVariableParserImpl, prePostCdScriptHistoryServiceImpl, scopedVariableCMCSManagerImpl, workflowServiceImpl, imageDigestPolicyServiceImpl, userServiceImpl, clientImpl, helmAppServiceImpl, enforcerUtilImpl, userDeploymentRequestServiceImpl, helmAppClientImpl, eventSimpleFactoryImpl, eventRESTClientImpl, environmentVariables, appRepositoryImpl, ciPipelineMaterialRepositoryImpl, imageScanHistoryReadServiceImpl, imageScanDeployInfoReadServiceImpl, imageScanDeployInfoServiceImpl, pipelineRepositoryImpl, pipelineOverrideRepositoryImpl, manifestPushConfigRepositoryImpl, chartRepositoryImpl, environmentRepositoryImpl, cdWorkflowRepositoryImpl, ciWorkflowRepositoryImpl, ciArtifactRepositoryImpl, ciTemplateReadServiceImpl, gitMaterialReadServiceImpl, appLabelRepositoryImpl, ciPipelineRepositoryImpl, appWorkflowRepositoryImpl, dockerArtifactStoreRepositoryImpl, imageScanServiceImpl, k8sServiceImpl, transactionUtilImpl, deploymentConfigServiceImpl, ciCdPipelineOrchestratorImpl, gitOperationServiceImpl, attributesServiceImpl, clusterRepositoryImpl, cdWorkflowRunnerServiceImpl) if err != nil { return nil, err } commonArtifactServiceImpl := artifacts.NewCommonArtifactServiceImpl(sugaredLogger, ciArtifactRepositoryImpl) - workflowDagExecutorImpl := dag.NewWorkflowDagExecutorImpl(sugaredLogger, pipelineRepositoryImpl, cdWorkflowRepositoryImpl, ciArtifactRepositoryImpl, enforcerUtilImpl, appWorkflowRepositoryImpl, pipelineStageServiceImpl, ciWorkflowRepositoryImpl, ciPipelineRepositoryImpl, pipelineStageRepositoryImpl, globalPluginRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, customTagServiceImpl, pipelineStatusTimelineServiceImpl, helmAppServiceImpl, cdWorkflowCommonServiceImpl, triggerServiceImpl, userDeploymentRequestServiceImpl, manifestCreationServiceImpl, commonArtifactServiceImpl, deploymentConfigServiceImpl, runnable, imageScanHistoryRepositoryImpl, imageScanServiceImpl) + workflowDagExecutorImpl := dag.NewWorkflowDagExecutorImpl(sugaredLogger, pipelineRepositoryImpl, cdWorkflowRepositoryImpl, ciArtifactRepositoryImpl, enforcerUtilImpl, appWorkflowRepositoryImpl, pipelineStageServiceImpl, ciWorkflowRepositoryImpl, ciPipelineRepositoryImpl, pipelineStageRepositoryImpl, globalPluginRepositoryImpl, eventRESTClientImpl, eventSimpleFactoryImpl, customTagServiceImpl, pipelineStatusTimelineServiceImpl, cdWorkflowRunnerServiceImpl, ciServiceImpl, helmAppServiceImpl, cdWorkflowCommonServiceImpl, triggerServiceImpl, userDeploymentRequestServiceImpl, manifestCreationServiceImpl, commonArtifactServiceImpl, deploymentConfigServiceImpl, runnable, imageScanHistoryRepositoryImpl, imageScanServiceImpl) externalCiRestHandlerImpl := restHandler.NewExternalCiRestHandlerImpl(sugaredLogger, validate, userServiceImpl, enforcerImpl, workflowDagExecutorImpl) pubSubClientRestHandlerImpl := restHandler.NewPubSubClientRestHandlerImpl(pubSubClientServiceImpl, sugaredLogger, ciCdConfig) webhookRouterImpl := router.NewWebhookRouterImpl(gitWebhookRestHandlerImpl, pipelineConfigRestHandlerImpl, externalCiRestHandlerImpl, pubSubClientRestHandlerImpl) @@ -757,7 +762,7 @@ func InitializeApp() (*App, error) { deleteServiceFullModeImpl := delete2.NewDeleteServiceFullModeImpl(sugaredLogger, gitMaterialReadServiceImpl, gitRegistryConfigImpl, ciTemplateRepositoryImpl, dockerRegistryConfigImpl, dockerArtifactStoreRepositoryImpl) gitProviderRestHandlerImpl := restHandler.NewGitProviderRestHandlerImpl(dockerRegistryConfigImpl, sugaredLogger, gitRegistryConfigImpl, userServiceImpl, validate, enforcerImpl, teamServiceImpl, deleteServiceFullModeImpl, gitProviderReadServiceImpl) gitProviderRouterImpl := router.NewGitProviderRouterImpl(gitProviderRestHandlerImpl) - gitHostRepositoryImpl := repository25.NewGitHostRepositoryImpl(db) + gitHostRepositoryImpl := repository26.NewGitHostRepositoryImpl(db) gitHostConfigImpl := gitHost.NewGitHostConfigImpl(gitHostRepositoryImpl, sugaredLogger) gitHostReadServiceImpl := read16.NewGitHostReadServiceImpl(sugaredLogger, gitHostRepositoryImpl, attributesServiceImpl) gitHostRestHandlerImpl := restHandler.NewGitHostRestHandlerImpl(sugaredLogger, gitHostConfigImpl, userServiceImpl, validate, enforcerImpl, clientImpl, gitProviderReadServiceImpl, gitHostReadServiceImpl) @@ -787,7 +792,7 @@ func InitializeApp() (*App, error) { chartRefRouterImpl := router.NewChartRefRouterImpl(chartRefRestHandlerImpl) configMapRestHandlerImpl := restHandler.NewConfigMapRestHandlerImpl(pipelineBuilderImpl, sugaredLogger, chartServiceImpl, userServiceImpl, teamServiceImpl, enforcerImpl, pipelineRepositoryImpl, enforcerUtilImpl, configMapServiceImpl) configMapRouterImpl := router.NewConfigMapRouterImpl(configMapRestHandlerImpl) - k8sResourceHistoryRepositoryImpl := repository26.NewK8sResourceHistoryRepositoryImpl(db, sugaredLogger) + k8sResourceHistoryRepositoryImpl := repository27.NewK8sResourceHistoryRepositoryImpl(db, sugaredLogger) k8sResourceHistoryServiceImpl := kubernetesResourceAuditLogs.Newk8sResourceHistoryServiceImpl(k8sResourceHistoryRepositoryImpl, sugaredLogger, appRepositoryImpl, environmentRepositoryImpl) ephemeralContainersRepositoryImpl := repository5.NewEphemeralContainersRepositoryImpl(db, transactionUtilImpl) ephemeralContainerServiceImpl := cluster.NewEphemeralContainerServiceImpl(ephemeralContainersRepositoryImpl, sugaredLogger) @@ -799,9 +804,9 @@ func InitializeApp() (*App, error) { } argoApplicationServiceExtendedImpl := argoApplication.NewArgoApplicationServiceExtendedServiceImpl(sugaredLogger, clusterRepositoryImpl, k8sServiceImpl, helmAppClientImpl, helmAppServiceImpl, k8sApplicationServiceImpl, argoApplicationConfigServiceImpl, argoClientWrapperServiceImpl) installedAppResourceServiceImpl := resource.NewInstalledAppResourceServiceImpl(sugaredLogger, installedAppRepositoryImpl, appStoreApplicationVersionRepositoryImpl, argoClientWrapperServiceImpl, acdAuthConfig, installedAppVersionHistoryRepositoryImpl, helmAppServiceImpl, helmAppReadServiceImpl, appStatusServiceImpl, k8sCommonServiceImpl, k8sApplicationServiceImpl, k8sServiceImpl, deploymentConfigServiceImpl, ociRegistryConfigRepositoryImpl, argoApplicationServiceExtendedImpl) - chartGroupEntriesRepositoryImpl := repository27.NewChartGroupEntriesRepositoryImpl(db, sugaredLogger) - chartGroupReposotoryImpl := repository27.NewChartGroupReposotoryImpl(db, sugaredLogger) - chartGroupDeploymentRepositoryImpl := repository27.NewChartGroupDeploymentRepositoryImpl(db, sugaredLogger) + chartGroupEntriesRepositoryImpl := repository28.NewChartGroupEntriesRepositoryImpl(db, sugaredLogger) + chartGroupReposotoryImpl := repository28.NewChartGroupReposotoryImpl(db, sugaredLogger) + chartGroupDeploymentRepositoryImpl := repository28.NewChartGroupDeploymentRepositoryImpl(db, sugaredLogger) appStoreVersionValuesRepositoryImpl := appStoreValuesRepository.NewAppStoreVersionValuesRepositoryImpl(sugaredLogger, db) appStoreRepositoryImpl := appStoreDiscoverRepository.NewAppStoreRepositoryImpl(sugaredLogger, db) clusterInstalledAppsRepositoryImpl := repository3.NewClusterInstalledAppsRepositoryImpl(db, sugaredLogger) @@ -819,7 +824,7 @@ func InitializeApp() (*App, error) { return nil, err } cdPipelineEventPublishServiceImpl := out.NewCDPipelineEventPublishServiceImpl(sugaredLogger, pubSubClientServiceImpl) - workflowStatusServiceImpl, err := status2.NewWorkflowStatusServiceImpl(sugaredLogger, workflowDagExecutorImpl, pipelineStatusTimelineServiceImpl, appServiceImpl, appStatusServiceImpl, acdConfig, appServiceConfig, pipelineStatusSyncDetailServiceImpl, argoClientWrapperServiceImpl, cdPipelineEventPublishServiceImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, installedAppRepositoryImpl, installedAppReadServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineRepositoryImpl, appListingServiceImpl, deploymentConfigServiceImpl) + workflowStatusServiceImpl, err := status2.NewWorkflowStatusServiceImpl(sugaredLogger, workflowDagExecutorImpl, pipelineStatusTimelineServiceImpl, appServiceImpl, appStatusServiceImpl, acdConfig, appServiceConfig, pipelineStatusSyncDetailServiceImpl, argoClientWrapperServiceImpl, cdPipelineEventPublishServiceImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, installedAppRepositoryImpl, installedAppReadServiceImpl, pipelineStatusTimelineRepositoryImpl, pipelineRepositoryImpl, appListingServiceImpl, deploymentConfigServiceImpl, cdWorkflowRunnerServiceImpl) if err != nil { return nil, err } @@ -933,7 +938,7 @@ func InitializeApp() (*App, error) { pipelineTriggerRouterImpl := trigger2.NewPipelineTriggerRouter(pipelineTriggerRestHandlerImpl, sseSSE) webhookDataRestHandlerImpl := webhook.NewWebhookDataRestHandlerImpl(sugaredLogger, userServiceImpl, ciPipelineMaterialRepositoryImpl, enforcerUtilImpl, enforcerImpl, clientImpl, webhookEventDataConfigImpl) pipelineConfigRouterImpl := configure2.NewPipelineRouterImpl(pipelineConfigRestHandlerImpl, webhookDataRestHandlerImpl) - prePostCiScriptHistoryRepositoryImpl := repository20.NewPrePostCiScriptHistoryRepositoryImpl(sugaredLogger, db) + prePostCiScriptHistoryRepositoryImpl := repository21.NewPrePostCiScriptHistoryRepositoryImpl(sugaredLogger, db) prePostCiScriptHistoryServiceImpl := history.NewPrePostCiScriptHistoryServiceImpl(sugaredLogger, prePostCiScriptHistoryRepositoryImpl) pipelineHistoryRestHandlerImpl := history2.NewPipelineHistoryRestHandlerImpl(sugaredLogger, userServiceImpl, enforcerImpl, pipelineStrategyHistoryServiceImpl, deploymentTemplateHistoryServiceImpl, configMapHistoryServiceImpl, prePostCiScriptHistoryServiceImpl, prePostCdScriptHistoryServiceImpl, enforcerUtilImpl, deployedConfigurationHistoryServiceImpl) pipelineHistoryRouterImpl := history3.NewPipelineHistoryRouterImpl(pipelineHistoryRestHandlerImpl) @@ -1048,9 +1053,8 @@ func InitializeApp() (*App, error) { muxRouter := router.NewMuxRouter(sugaredLogger, environmentRouterImpl, clusterRouterImpl, webhookRouterImpl, userAuthRouterImpl, gitProviderRouterImpl, gitHostRouterImpl, dockerRegRouterImpl, notificationRouterImpl, teamRouterImpl, userRouterImpl, chartRefRouterImpl, configMapRouterImpl, appStoreRouterImpl, chartRepositoryRouterImpl, releaseMetricsRouterImpl, deploymentGroupRouterImpl, batchOperationRouterImpl, chartGroupRouterImpl, imageScanRouterImpl, policyRouterImpl, gitOpsConfigRouterImpl, dashboardRouterImpl, attributesRouterImpl, userAttributesRouterImpl, commonRouterImpl, grafanaRouterImpl, ssoLoginRouterImpl, telemetryRouterImpl, telemetryEventClientImplExtended, bulkUpdateRouterImpl, webhookListenerRouterImpl, appRouterImpl, coreAppRouterImpl, helmAppRouterImpl, k8sApplicationRouterImpl, pProfRouterImpl, deploymentConfigRouterImpl, dashboardTelemetryRouterImpl, commonDeploymentRouterImpl, externalLinkRouterImpl, globalPluginRouterImpl, moduleRouterImpl, serverRouterImpl, apiTokenRouterImpl, cdApplicationStatusUpdateHandlerImpl, k8sCapacityRouterImpl, webhookHelmRouterImpl, globalCMCSRouterImpl, userTerminalAccessRouterImpl, jobRouterImpl, ciStatusUpdateCronImpl, resourceGroupingRouterImpl, rbacRoleRouterImpl, scopedVariableRouterImpl, ciTriggerCronImpl, proxyRouterImpl, deploymentConfigurationRouterImpl, infraConfigRouterImpl, argoApplicationRouterImpl, devtronResourceRouterImpl, fluxApplicationRouterImpl, scanningResultRouterImpl) loggingMiddlewareImpl := util4.NewLoggingMiddlewareImpl(userServiceImpl) cdWorkflowServiceImpl := cd.NewCdWorkflowServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) - cdWorkflowRunnerServiceImpl := cd.NewCdWorkflowRunnerServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) cdWorkflowRunnerReadServiceImpl := read15.NewCdWorkflowRunnerReadServiceImpl(sugaredLogger, cdWorkflowRepositoryImpl) - webhookServiceImpl := pipeline.NewWebhookServiceImpl(ciArtifactRepositoryImpl, sugaredLogger, ciPipelineRepositoryImpl, ciWorkflowRepositoryImpl, cdWorkflowCommonServiceImpl) + webhookServiceImpl := pipeline.NewWebhookServiceImpl(ciArtifactRepositoryImpl, sugaredLogger, ciPipelineRepositoryImpl, ciWorkflowRepositoryImpl, cdWorkflowCommonServiceImpl, workFlowStageStatusServiceImpl, ciServiceImpl) workflowEventProcessorImpl, err := in.NewWorkflowEventProcessorImpl(sugaredLogger, pubSubClientServiceImpl, cdWorkflowServiceImpl, cdWorkflowReadServiceImpl, cdWorkflowRunnerServiceImpl, cdWorkflowRunnerReadServiceImpl, workflowDagExecutorImpl, ciHandlerImpl, cdHandlerImpl, eventSimpleFactoryImpl, eventRESTClientImpl, triggerServiceImpl, deployedAppServiceImpl, webhookServiceImpl, validate, environmentVariables, cdWorkflowCommonServiceImpl, cdPipelineConfigServiceImpl, userDeploymentRequestServiceImpl, pipelineRepositoryImpl, ciArtifactRepositoryImpl, cdWorkflowRepositoryImpl, deploymentConfigServiceImpl) if err != nil { return nil, err