Skip to content

Commit

Permalink
Feat: Bulk build trigger (#2546)
Browse files Browse the repository at this point in the history
* bulk ci trigger

* handling linked ci pipeline for bulk build trigger

* bulk ci trigger - reponse modifications
  • Loading branch information
vikramdevtron authored Oct 28, 2022
1 parent 5d43f23 commit f45ae13
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 5 deletions.
37 changes: 37 additions & 0 deletions api/restHandler/BulkUpdateRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type BulkUpdateRestHandler interface {
BulkHibernate(w http.ResponseWriter, r *http.Request)
BulkUnHibernate(w http.ResponseWriter, r *http.Request)
BulkDeploy(w http.ResponseWriter, r *http.Request)
BulkBuildTrigger(w http.ResponseWriter, r *http.Request)
}
type BulkUpdateRestHandlerImpl struct {
pipelineBuilder pipeline.PipelineBuilder
Expand Down Expand Up @@ -357,6 +358,42 @@ func (handler BulkUpdateRestHandlerImpl) BulkDeploy(w http.ResponseWriter, r *ht
common.WriteJsonResp(w, nil, response, http.StatusOK)
}

func (handler BulkUpdateRestHandlerImpl) BulkBuildTrigger(w http.ResponseWriter, r *http.Request) {
userId, err := handler.userAuthService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
return
}
decoder := json.NewDecoder(r.Body)
var request pipeline.BulkApplicationForEnvironmentPayload
err = decoder.Decode(&request)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
request.UserId = userId
err = handler.validator.Struct(request)
if err != nil {
handler.logger.Errorw("validation err", "err", err, "request", request)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
acdToken, err := handler.argoUserService.GetLatestDevtronArgoCdUserToken()
if err != nil {
handler.logger.Errorw("error in getting acd token", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
ctx := context.WithValue(r.Context(), "token", acdToken)
token := r.Header.Get("token")
response, err := handler.bulkUpdateService.BulkBuildTrigger(&request, ctx, w, token, handler.checkAuthForBulkActions)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
common.WriteJsonResp(w, nil, response, http.StatusOK)
}

func (handler BulkUpdateRestHandlerImpl) checkAuthForBulkActions(token string, appObject string, envObject string) bool {
if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, strings.ToLower(appObject)); !ok {
return false
Expand Down
1 change: 1 addition & 0 deletions api/router/BulkUpdateRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ func (router BulkUpdateRouterImpl) initBulkUpdateRouter(bulkRouter *mux.Router)
bulkRouter.Path("/v1beta1/hibernate").HandlerFunc(router.restHandler.BulkHibernate).Methods("POST")
bulkRouter.Path("/v1beta1/unhibernate").HandlerFunc(router.restHandler.BulkUnHibernate).Methods("POST")
bulkRouter.Path("/v1beta1/deploy").HandlerFunc(router.restHandler.BulkDeploy).Methods("POST")
bulkRouter.Path("/v1beta1/build").HandlerFunc(router.restHandler.BulkBuildTrigger).Methods("POST")

}
115 changes: 114 additions & 1 deletion pkg/pipeline/BulkUpdateService.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/devtron-labs/devtron/api/bean"
client "github.com/devtron-labs/devtron/api/helm-app"
"github.com/devtron-labs/devtron/internal/sql/repository/app"
bean2 "github.com/devtron-labs/devtron/pkg/bean"
"github.com/devtron-labs/devtron/pkg/chart"
chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository"
repository2 "github.com/devtron-labs/devtron/pkg/cluster/repository"
Expand Down Expand Up @@ -134,6 +135,7 @@ type BulkUpdateService interface {
BulkHibernate(request *BulkApplicationForEnvironmentPayload, ctx context.Context, w http.ResponseWriter, token string, checkAuthForBulkActions func(token string, appObject string, envObject string) bool) (*BulkApplicationForEnvironmentResponse, error)
BulkUnHibernate(request *BulkApplicationForEnvironmentPayload, ctx context.Context, w http.ResponseWriter, token string, checkAuthForBulkActions func(token string, appObject string, envObject string) bool) (*BulkApplicationForEnvironmentResponse, error)
BulkDeploy(request *BulkApplicationForEnvironmentPayload, ctx context.Context, w http.ResponseWriter, token string, checkAuthForBulkActions func(token string, appObject string, envObject string) bool) (*BulkApplicationForEnvironmentResponse, error)
BulkBuildTrigger(request *BulkApplicationForEnvironmentPayload, ctx context.Context, w http.ResponseWriter, token string, checkAuthForBulkActions func(token string, appObject string, envObject string) bool) (*BulkApplicationForEnvironmentResponse, error)
}

type BulkUpdateServiceImpl struct {
Expand Down Expand Up @@ -163,6 +165,8 @@ type BulkUpdateServiceImpl struct {
helmAppService client.HelmAppService
enforcerUtil rbac.EnforcerUtil
enforcerUtilHelm rbac.EnforcerUtilHelm
ciHandler CiHandler
ciPipelineRepository pipelineConfig.CiPipelineRepository
}

func NewBulkUpdateServiceImpl(bulkUpdateRepository bulkUpdate.BulkUpdateRepository,
Expand All @@ -187,7 +191,7 @@ func NewBulkUpdateServiceImpl(bulkUpdateRepository bulkUpdate.BulkUpdateReposito
configMapHistoryService history.ConfigMapHistoryService, workflowDagExecutor WorkflowDagExecutor,
cdWorkflowRepository pipelineConfig.CdWorkflowRepository, pipelineBuilder PipelineBuilder,
helmAppService client.HelmAppService, enforcerUtil rbac.EnforcerUtil,
enforcerUtilHelm rbac.EnforcerUtilHelm) *BulkUpdateServiceImpl {
enforcerUtilHelm rbac.EnforcerUtilHelm, ciHandler CiHandler, ciPipelineRepository pipelineConfig.CiPipelineRepository) *BulkUpdateServiceImpl {
return &BulkUpdateServiceImpl{
bulkUpdateRepository: bulkUpdateRepository,
chartRepository: chartRepository,
Expand Down Expand Up @@ -215,6 +219,8 @@ func NewBulkUpdateServiceImpl(bulkUpdateRepository bulkUpdate.BulkUpdateReposito
helmAppService: helmAppService,
enforcerUtil: enforcerUtil,
enforcerUtilHelm: enforcerUtilHelm,
ciHandler: ciHandler,
ciPipelineRepository: ciPipelineRepository,
}
}

Expand Down Expand Up @@ -1247,3 +1253,110 @@ func (impl BulkUpdateServiceImpl) BulkDeploy(request *BulkApplicationForEnvironm
bulkOperationResponse.Response = response
return bulkOperationResponse, nil
}

func (impl BulkUpdateServiceImpl) BulkBuildTrigger(request *BulkApplicationForEnvironmentPayload, ctx context.Context, w http.ResponseWriter, token string, checkAuthForBulkActions func(token string, appObject string, envObject string) bool) (*BulkApplicationForEnvironmentResponse, error) {
var pipelines []*pipelineConfig.Pipeline
var err error
if len(request.AppIdIncludes) > 0 {
pipelines, err = impl.pipelineRepository.FindActiveByInFilter(request.EnvId, request.AppIdIncludes)
} else if len(request.AppIdExcludes) > 0 {
pipelines, err = impl.pipelineRepository.FindActiveByNotFilter(request.EnvId, request.AppIdExcludes)
} else {
pipelines, err = impl.pipelineRepository.FindActiveByEnvId(request.EnvId)
}
if err != nil {
impl.logger.Errorw("error in fetching pipelines", "envId", request.EnvId, "err", err)
return nil, err
}

latestCommitsMap := map[int]bean2.CiTriggerRequest{}
ciCompletedStatus := map[int]bool{}
for _, pipeline := range pipelines {
if _, ok := latestCommitsMap[pipeline.CiPipelineId]; !ok {
ciPipelineId := 0
ciPipeline, err := impl.ciPipelineRepository.FindById(pipeline.CiPipelineId)
if err != nil {
impl.logger.Errorw("error in fetching ci pipeline", "CiPipelineId", pipeline.CiPipelineId, "err", err)
return nil, err
}
ciPipelineId = ciPipeline.Id
if ciPipeline.IsExternal {
if _, ok := latestCommitsMap[ciPipeline.ParentCiPipeline]; ok {
//skip linked ci pipeline for fetching materials if its parent already fetched.
continue
}
ciPipelineId = ciPipeline.ParentCiPipeline
}
materialResponse, err := impl.ciHandler.FetchMaterialsByPipelineId(ciPipelineId)
if err != nil {
impl.logger.Errorw("error in fetching ci pipeline materials", "CiPipelineId", ciPipelineId, "err", err)
return nil, err
}
var materialId int
var commitHash string
for _, material := range materialResponse {
materialId = material.Id
if len(material.History) > 0 {
commitHash = material.History[0].Commit
}
}
var ciMaterials []bean2.CiPipelineMaterial
ciMaterials = append(ciMaterials, bean2.CiPipelineMaterial{
Id: materialId,
GitCommit: bean2.GitCommit{Commit: commitHash},
})
ciTriggerRequest := bean2.CiTriggerRequest{
PipelineId: ciPipelineId,
CiPipelineMaterial: ciMaterials,
TriggeredBy: request.UserId,
InvalidateCache: false,
}
latestCommitsMap[ciPipelineId] = ciTriggerRequest
ciCompletedStatus[ciPipelineId] = false
}
}

response := make(map[string]map[string]bool)
for _, pipeline := range pipelines {
ciCompleted := ciCompletedStatus[pipeline.CiPipelineId]
if !ciCompleted {
appKey := fmt.Sprintf("%d_%s", pipeline.AppId, pipeline.App.AppName)
pipelineKey := fmt.Sprintf("%d", pipeline.CiPipelineId)
success := true
if _, ok := response[appKey]; !ok {
pResponse := make(map[string]bool)
pResponse[pipelineKey] = false
response[appKey] = pResponse
}
appObject := impl.enforcerUtil.GetAppRBACNameByAppId(pipeline.AppId)
envObject := impl.enforcerUtil.GetEnvRBACNameByAppId(pipeline.AppId, pipeline.EnvironmentId)
isValidAuth := checkAuthForBulkActions(token, appObject, envObject)
if !isValidAuth {
//skip hibernate for the app if user does not have access on that
pipelineResponse := response[appKey]
pipelineResponse[pipelineKey] = false
response[appKey] = pipelineResponse
continue
}

ciTriggerRequest := latestCommitsMap[pipeline.CiPipelineId]
_, err = impl.ciHandler.HandleCIManual(ciTriggerRequest)
if err != nil {
impl.logger.Errorw("service err, HandleCIManual", "err", err, "ciTriggerRequest", ciTriggerRequest)
//return nil, err
pipelineResponse := response[appKey]
pipelineResponse[appKey] = false
response[appKey] = pipelineResponse
}

pipelineResponse := response[appKey]
pipelineResponse[pipelineKey] = success
response[appKey] = pipelineResponse
ciCompletedStatus[pipeline.CiPipelineId] = true
}
}
bulkOperationResponse := &BulkApplicationForEnvironmentResponse{}
bulkOperationResponse.BulkApplicationForEnvironmentPayload = *request
bulkOperationResponse.Response = response
return bulkOperationResponse, nil
}
7 changes: 3 additions & 4 deletions wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f45ae13

Please sign in to comment.