diff --git a/api/externalLink/ExternalLinkRestHandler.go b/api/externalLink/ExternalLinkRestHandler.go index 997bd9dec7..785eafe2b8 100644 --- a/api/externalLink/ExternalLinkRestHandler.go +++ b/api/externalLink/ExternalLinkRestHandler.go @@ -37,6 +37,7 @@ type ExternalLinkRestHandler interface { CreateExternalLinks(w http.ResponseWriter, r *http.Request) GetExternalLinkMonitoringTools(w http.ResponseWriter, r *http.Request) GetExternalLinks(w http.ResponseWriter, r *http.Request) + GetExternalLinksV2(w http.ResponseWriter, r *http.Request) UpdateExternalLink(w http.ResponseWriter, r *http.Request) DeleteExternalLink(w http.ResponseWriter, r *http.Request) // Update is_active to false link } @@ -134,6 +135,7 @@ func (impl ExternalLinkRestHandlerImpl) GetExternalLinkMonitoringTools(w http.Re } common.WriteJsonResp(w, err, res, http.StatusOK) } + func (impl ExternalLinkRestHandlerImpl) GetExternalLinks(w http.ResponseWriter, r *http.Request) { userId, err := impl.userService.GetLoggedInUser(r) if userId == 0 || err != nil { @@ -146,6 +148,65 @@ func (impl ExternalLinkRestHandlerImpl) GetExternalLinks(w http.ResponseWriter, linkType := v.Get("type") identifier := v.Get("identifier") + token := r.Header.Get("token") + if len(identifier) == 0 && len(linkType) == 0 && len(clusterId) == 0 { + if ok := impl.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); !ok { + common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden) + return + } + clusterIdNumber := 0 + res, err := impl.externalLinkService.FetchAllActiveLinksByLinkIdentifier(nil, clusterIdNumber) + if err != nil { + impl.logger.Errorw("service err, FetchAllActive", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + common.WriteJsonResp(w, err, res, http.StatusOK) + return + + } else if len(identifier) != 0 && len(linkType) != 0 { //api to get external links from app-level external links tab and from app-details page + clusterIdNumber := 0 + if len(clusterId) != 0 { //api call from app-detail page + clusterIdNumber, err = strconv.Atoi(clusterId) + if err != nil { + impl.logger.Errorw("error occurred while parsing cluster_id", "clusterId", clusterId, "err", err) + common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return + } + } + linkIdentifier := &externalLink.LinkIdentifier{ + Type: linkType, + Identifier: identifier, + ClusterId: 0, + } + res, err := impl.externalLinkService.FetchAllActiveLinksByLinkIdentifier(linkIdentifier, clusterIdNumber) + if err != nil { + impl.logger.Errorw("service err, FetchAllActive", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + common.WriteJsonResp(w, err, res, http.StatusOK) + return + } + + impl.logger.Errorw("invalid request, FetchAllActive external links", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return + +} + +func (impl ExternalLinkRestHandlerImpl) GetExternalLinksV2(w http.ResponseWriter, r *http.Request) { + userId, err := impl.userService.GetLoggedInUser(r) + if userId == 0 || err != nil { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } + + v := r.URL.Query() + clusterId := v.Get("clusterId") + linkType := v.Get("type") + identifier := v.Get("identifier") + externalLinkAndMonitoringTools := externalLink.ExternalLinkAndMonitoringToolDTO{} externalLinks := []*externalLink.ExternalLinkDto{} diff --git a/api/externalLink/ExternalLinkRouter.go b/api/externalLink/ExternalLinkRouter.go index 07abfef60b..93de600943 100644 --- a/api/externalLink/ExternalLinkRouter.go +++ b/api/externalLink/ExternalLinkRouter.go @@ -19,6 +19,7 @@ func (impl ExternalLinkRouterImpl) InitExternalLinkRouter(configRouter *mux.Rout configRouter.Path("").HandlerFunc(impl.externalLinkRestHandler.CreateExternalLinks).Methods("POST") configRouter.Path("/tools").HandlerFunc(impl.externalLinkRestHandler.GetExternalLinkMonitoringTools).Methods("GET") configRouter.Path("").HandlerFunc(impl.externalLinkRestHandler.GetExternalLinks).Methods("GET") + configRouter.Path("/v2").HandlerFunc(impl.externalLinkRestHandler.GetExternalLinksV2).Methods("GET") configRouter.Path("").HandlerFunc(impl.externalLinkRestHandler.UpdateExternalLink).Methods("PUT") configRouter.Path("").HandlerFunc(impl.externalLinkRestHandler.DeleteExternalLink).Queries("id", "{id}").Methods("DELETE") } diff --git a/api/restHandler/AppListingRestHandler.go b/api/restHandler/AppListingRestHandler.go index d9a6ab599c..c88ea33b42 100644 --- a/api/restHandler/AppListingRestHandler.go +++ b/api/restHandler/AppListingRestHandler.go @@ -868,7 +868,7 @@ func (handler AppListingRestHandlerImpl) FetchOverviewAppsByEnvironment(w http.R rbacObjectsWithAppId := handler.enforcerUtil.GetRbacObjectsByAppIds(appIds) rbacObjects := make([]string, len(rbacObjectsWithAppId)) itr := 0 - for _, object := range rbacObjects { + for _, object := range rbacObjectsWithAppId { rbacObjects[itr] = object itr++ } diff --git a/api/restHandler/app/PipelineConfigRestHandler.go b/api/restHandler/app/PipelineConfigRestHandler.go index 9316252ccf..6181c6fe95 100644 --- a/api/restHandler/app/PipelineConfigRestHandler.go +++ b/api/restHandler/app/PipelineConfigRestHandler.go @@ -521,6 +521,7 @@ func (handler PipelineConfigRestHandlerImpl) FetchAppWorkflowStatusForTriggerVie } //RBAC CHECK + apiVersion := vars["version"] triggerWorkflowStatus := pipelineConfig.TriggerWorkflowStatus{} var ciWorkflowStatus []*pipelineConfig.CiWorkflowStatus var err1 error @@ -529,7 +530,11 @@ func (handler PipelineConfigRestHandlerImpl) FetchAppWorkflowStatusForTriggerVie wg := sync.WaitGroup{} wg.Add(2) go func() { - ciWorkflowStatus, err = handler.ciHandler.FetchCiStatusForTriggerView(appId) + if apiVersion == "v2" { + ciWorkflowStatus, err = handler.ciHandler.FetchCiStatusForTriggerViewV1(appId) + } else { + ciWorkflowStatus, err = handler.ciHandler.FetchCiStatusForTriggerView(appId) + } wg.Done() }() diff --git a/api/router/PipelineConfigRouter.go b/api/router/PipelineConfigRouter.go index 8cc9183f9c..49296d9273 100644 --- a/api/router/PipelineConfigRouter.go +++ b/api/router/PipelineConfigRouter.go @@ -152,6 +152,7 @@ func (router PipelineConfigRouterImpl) initPipelineConfigRouter(configRouter *mu configRouter.Path("/cd/configmap-secrets/{pipelineId}").HandlerFunc(router.restHandler.GetConfigmapSecretsForDeploymentStages).Methods("GET") configRouter.Path("/workflow/status/{appId}").HandlerFunc(router.restHandler.FetchAppWorkflowStatusForTriggerView).Methods("GET") + configRouter.Path("/workflow/status/{appId}/{version}").HandlerFunc(router.restHandler.FetchAppWorkflowStatusForTriggerView).Methods("GET") configRouter.Path("/material-info/{appId}/{ciArtifactId}").HandlerFunc(router.restHandler.FetchMaterialInfo).Methods("GET") configRouter.Path("/ci-pipeline/webhook-payload/{pipelineMaterialId}").HandlerFunc(router.webhookDataRestHandler.GetWebhookPayloadDataForPipelineMaterialId).Methods("GET") diff --git a/pkg/app/AppListingService.go b/pkg/app/AppListingService.go index ea895ed683..fbe35d5a78 100644 --- a/pkg/app/AppListingService.go +++ b/pkg/app/AppListingService.go @@ -386,6 +386,35 @@ func (impl AppListingServiceImpl) FetchAppsByEnvironmentV2(fetchAppListingReques impl.Logger.Errorw("error in fetching app list", "error", err, "filter", appListingFilter) return []*bean.AppEnvironmentContainer{}, appSize, err } + + envContainersMap := make(map[int][]*bean.AppEnvironmentContainer) + envIds := make([]int, 0) + envsSet := make(map[int]bool) + + for _, container := range envContainers { + if container.EnvironmentId != 0 { + if _, ok := envContainersMap[container.EnvironmentId]; !ok { + envContainersMap[container.EnvironmentId] = make([]*bean.AppEnvironmentContainer, 0) + } + envContainersMap[container.EnvironmentId] = append(envContainersMap[container.EnvironmentId], container) + if _, ok := envsSet[container.EnvironmentId]; !ok { + envIds = append(envIds, container.EnvironmentId) + envsSet[container.EnvironmentId] = true + } + } + } + envClusterInfos, err := impl.environmentRepository.FindEnvClusterInfosByIds(envIds) + if err != nil { + impl.Logger.Errorw("error in envClusterInfos list", "error", err, "envIds", envIds) + return []*bean.AppEnvironmentContainer{}, appSize, err + } + for _, info := range envClusterInfos { + for _, container := range envContainersMap[info.Id] { + container.Namespace = info.Namespace + container.ClusterName = info.ClusterName + container.EnvironmentName = info.Name + } + } return envContainers, appSize, nil } diff --git a/pkg/bean/app.go b/pkg/bean/app.go index edb6e81f32..23327bc683 100644 --- a/pkg/bean/app.go +++ b/pkg/bean/app.go @@ -299,6 +299,7 @@ type CiConfigRequest struct { UpdatedOn time.Time `sql:"updated_on,type:timestamptz"` UpdatedBy int32 `sql:"updated_by,type:integer"` IsJob bool `json:"-"` + CiGitMaterialId int `json:"ciGitConfiguredId"` } type TestExecutorImageProperties struct { diff --git a/pkg/cluster/repository/EnvironmentRepository.go b/pkg/cluster/repository/EnvironmentRepository.go index b583089821..fe7bb5a92d 100644 --- a/pkg/cluster/repository/EnvironmentRepository.go +++ b/pkg/cluster/repository/EnvironmentRepository.go @@ -18,13 +18,21 @@ package repository import ( + "fmt" "github.com/devtron-labs/devtron/internal/sql/repository/appStatus" + "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" "github.com/go-pg/pg/orm" "go.uber.org/zap" ) +type EnvCluserInfo struct { + Id int `sql:"id"` + ClusterName string `sql:"cluster_name"` + Namespace string `sql:"namespace"` + Name string `sql:"name"` +} type Environment struct { tableName struct{} `sql:"environment" pg:",discard_unknown_columns"` Id int `sql:"id,pk"` @@ -66,6 +74,7 @@ type EnvironmentRepository interface { FindByEnvNameAndClusterIds(envName string, clusterIds []int) ([]*Environment, error) FindByClusterIdsWithFilter(clusterIds []int) ([]*Environment, error) FindAllActiveWithFilter() ([]*Environment, error) + FindEnvClusterInfosByIds([]int) ([]*EnvCluserInfo, error) } func NewEnvironmentRepositoryImpl(dbConnection *pg.DB, logger *zap.SugaredLogger, appStatusRepository appStatus.AppStatusRepository) *EnvironmentRepositoryImpl { @@ -96,6 +105,17 @@ func (repositoryImpl EnvironmentRepositoryImpl) FindOne(environment string) (*En return environmentCluster, err } +func (repositoryImpl EnvironmentRepositoryImpl) FindEnvClusterInfosByIds(envIds []int) ([]*EnvCluserInfo, error) { + query := "SELECT env.id as id,cluster.cluster_name,env.environment_name as name,env.namespace " + + " FROM environment env INNER JOIN cluster ON env.cluster_id = cluster.id " + if len(envIds) > 0 { + query += fmt.Sprintf(" WHERE env.id IN (%s)", helper.GetCommaSepratedString(envIds)) + } + res := make([]*EnvCluserInfo, 0) + _, err := repositoryImpl.dbConnection.Query(&res, query) + return res, err +} + func (repositoryImpl EnvironmentRepositoryImpl) FindByNamespaceAndClusterName(namespaces string, clusterName string) (*Environment, error) { environmentCluster := &Environment{} err := repositoryImpl.dbConnection. diff --git a/pkg/pipeline/CiHandler.go b/pkg/pipeline/CiHandler.go index a602b5f20c..e5d49947ac 100644 --- a/pkg/pipeline/CiHandler.go +++ b/pkg/pipeline/CiHandler.go @@ -67,6 +67,7 @@ type CiHandler interface { UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus) (int, error) FetchCiStatusForTriggerView(appId int) ([]*pipelineConfig.CiWorkflowStatus, error) + FetchCiStatusForTriggerViewV1(appId int) ([]*pipelineConfig.CiWorkflowStatus, error) RefreshMaterialByCiPipelineMaterialId(gitMaterialId int) (refreshRes *gitSensor.RefreshGitMaterialResponse, err error) FetchMaterialInfoByArtifactId(ciArtifactId int) (*GitTriggerInfoResponse, error) WriteToCreateTestSuites(pipelineId int, buildId int, triggeredBy int) @@ -1022,7 +1023,7 @@ func (impl *CiHandlerImpl) getLastSeenCommit(ciMaterialId int) (bean.GitCommit, return gitCommit, nil } -func (impl *CiHandlerImpl) FetchCiStatusForTriggerView(appId int) ([]*pipelineConfig.CiWorkflowStatus, error) { +func (impl *CiHandlerImpl) FetchCiStatusForTriggerViewV1(appId int) ([]*pipelineConfig.CiWorkflowStatus, error) { ciWorkflowStatuses, err := impl.ciWorkflowRepository.FIndCiWorkflowStatusesByAppId(appId) if err != nil && !util.IsErrNoRows(err) { impl.Logger.Errorw("err in fetching ciWorkflowStatuses from ciWorkflowRepository", "appId", appId, "err", err) @@ -1032,6 +1033,39 @@ func (impl *CiHandlerImpl) FetchCiStatusForTriggerView(appId int) ([]*pipelineCo return ciWorkflowStatuses, err } +func (impl *CiHandlerImpl) FetchCiStatusForTriggerView(appId int) ([]*pipelineConfig.CiWorkflowStatus, error) { + var ciWorkflowStatuses []*pipelineConfig.CiWorkflowStatus + + pipelines, err := impl.ciPipelineRepository.FindByAppId(appId) + if err != nil && err != pg.ErrNoRows { + impl.Logger.Errorw("error in fetching ci pipeline", "appId", appId, "err", err) + return ciWorkflowStatuses, err + } + for _, pipeline := range pipelines { + pipelineId := 0 + if pipeline.ParentCiPipeline == 0 { + pipelineId = pipeline.Id + } else { + pipelineId = pipeline.ParentCiPipeline + } + workflow, err := impl.ciWorkflowRepository.FindLastTriggeredWorkflow(pipelineId) + if err != nil && !util.IsErrNoRows(err) { + impl.Logger.Errorw("err", "pipelineId", pipelineId, "err", err) + return ciWorkflowStatuses, err + } + ciWorkflowStatus := &pipelineConfig.CiWorkflowStatus{} + ciWorkflowStatus.CiPipelineId = pipeline.Id + if workflow.Id > 0 { + ciWorkflowStatus.CiPipelineName = workflow.CiPipeline.Name + ciWorkflowStatus.CiStatus = workflow.Status + } else { + ciWorkflowStatus.CiStatus = "Not Triggered" + } + ciWorkflowStatuses = append(ciWorkflowStatuses, ciWorkflowStatus) + } + return ciWorkflowStatuses, nil +} + func (impl *CiHandlerImpl) FetchMaterialInfoByArtifactId(ciArtifactId int) (*GitTriggerInfoResponse, error) { ciArtifact, err := impl.ciArtifactRepository.Get(ciArtifactId) diff --git a/pkg/pipeline/PipelineBuilder.go b/pkg/pipeline/PipelineBuilder.go index caea61abae..f89cfce04f 100644 --- a/pkg/pipeline/PipelineBuilder.go +++ b/pkg/pipeline/PipelineBuilder.go @@ -1154,7 +1154,7 @@ func (impl PipelineBuilderImpl) UpdateCiTemplate(updateRequest *bean.CiConfigReq CreatedOn: originalCiConf.CreatedOn, CreatedBy: originalCiConf.CreatedBy, UpdatedOn: time.Now(), - UpdatedBy: updateRequest.UpdatedBy, + UpdatedBy: updateRequest.UserId, }, } @@ -4069,6 +4069,7 @@ func (impl PipelineBuilderImpl) GetCiPipelineByEnvironment(envId int, emailId st //parentCiPipelineIds = append(parentCiPipelineIds, pipeline.ParentCiPipeline) } ciPipelinesConfigByApp.CiPipelines = ciPipelineResp + ciPipelinesConfigByApp.CiGitMaterialId = ciPipelinesConfigByApp.CiBuildConfig.GitMaterialId ciPipelinesConfigByApps = append(ciPipelinesConfigByApps, ciPipelinesConfigByApp) }