Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 66 additions & 4 deletions api/cluster/ClusterRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ import (
"context"
"encoding/json"
"errors"
bean2 "github.com/devtron-labs/devtron/pkg/cluster/bean"
"github.com/devtron-labs/devtron/pkg/cluster/environment"
"github.com/devtron-labs/devtron/pkg/cluster/rbac"
"net/http"
"strconv"
"strings"
"time"

bean2 "github.com/devtron-labs/devtron/pkg/cluster/bean"
"github.com/devtron-labs/devtron/pkg/cluster/environment"
"github.com/devtron-labs/devtron/pkg/cluster/rbac"

"github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin"
"github.com/devtron-labs/devtron/pkg/auth/user"
"github.com/devtron-labs/devtron/pkg/genericNotes"
Expand Down Expand Up @@ -60,6 +61,7 @@ type ClusterRestHandler interface {
GetClusterNamespaces(w http.ResponseWriter, r *http.Request)
GetAllClusterNamespaces(w http.ResponseWriter, r *http.Request)
FindAllForClusterPermission(w http.ResponseWriter, r *http.Request)
FindByIds(w http.ResponseWriter, r *http.Request)
}

type ClusterRestHandlerImpl struct {
Expand Down Expand Up @@ -296,6 +298,59 @@ func (impl ClusterRestHandlerImpl) FindAll(w http.ResponseWriter, r *http.Reques
common.WriteJsonResp(w, err, result, http.StatusOK)
}

func (impl ClusterRestHandlerImpl) FindByIds(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("token")

// Parse clusterId query parameter
clusterIdsStr := r.URL.Query().Get("clusterId")
if clusterIdsStr == "" {
// If no clusterId parameter, return all clusters (same as FindAll)
impl.FindAll(w, r)
return
}

// Parse comma-separated cluster IDs
var clusterIds []int
clusterIdStrs := strings.Split(clusterIdsStr, ",")
for _, idStr := range clusterIdStrs {
idStr = strings.TrimSpace(idStr)
if idStr == "" {
continue
}
id, err := strconv.Atoi(idStr)
if err != nil {
impl.logger.Errorw("request err, FindByIds", "error", err, "clusterId", idStr)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
clusterIds = append(clusterIds, id)
}

if len(clusterIds) == 0 {
// If no valid cluster IDs, return empty result
common.WriteJsonResp(w, nil, []*bean2.ClusterBean{}, http.StatusOK)
return
}

clusterList, err := impl.clusterService.FindByIdsWithoutConfig(clusterIds)
if err != nil {
impl.logger.Errorw("service err, FindByIds", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}

// RBAC enforcer applying
var result []*bean2.ClusterBean
for _, item := range clusterList {
if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionGet, item.ClusterName); ok {
result = append(result, item)
}
}
//RBAC enforcer Ends

common.WriteJsonResp(w, err, result, http.StatusOK)
}

func (impl ClusterRestHandlerImpl) FindById(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
Expand Down Expand Up @@ -671,7 +726,14 @@ func (impl ClusterRestHandlerImpl) GetClusterNamespaces(w http.ResponseWriter, r

allClusterNamespaces, err := impl.clusterService.FindAllNamespacesByUserIdAndClusterId(userId, clusterId, isActionUserSuperAdmin)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
// Check if it's a cluster connectivity error and return appropriate status code
if err.Error() == cluster.ErrClusterNotReachable {
impl.logger.Errorw("cluster connectivity error in GetClusterNamespaces", "error", err, "clusterId", clusterId)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
} else {
impl.logger.Errorw("error in GetClusterNamespaces", "error", err, "clusterId", clusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
}
return
}
common.WriteJsonResp(w, nil, allClusterNamespaces, http.StatusOK)
Expand Down
5 changes: 5 additions & 0 deletions api/cluster/ClusterRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) {
Queries("id", "{id}").
HandlerFunc(impl.clusterRestHandler.FindNoteByClusterId)

clusterRouter.Path("").
Methods("GET").
Queries("clusterId", "{clusterId}").
HandlerFunc(impl.clusterRestHandler.FindByIds)

clusterRouter.Path("").
Methods("GET").
HandlerFunc(impl.clusterRestHandler.FindAll)
Expand Down
37 changes: 33 additions & 4 deletions pkg/cluster/ClusterService.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ import (
"context"
"encoding/json"
"fmt"
"log"
"net/url"
"sync"
"time"

"github.com/devtron-labs/common-lib/async"
informerBean "github.com/devtron-labs/common-lib/informer"
"github.com/devtron-labs/common-lib/utils/k8s/commonBean"
Expand All @@ -32,10 +37,6 @@ import (
"github.com/devtron-labs/devtron/pkg/cluster/read"
cronUtil "github.com/devtron-labs/devtron/util/cron"
"github.com/robfig/cron/v3"
"log"
"net/url"
"sync"
"time"

"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/devtron-labs/common-lib/utils/k8s"
Expand Down Expand Up @@ -75,6 +76,7 @@ type ClusterService interface {
FindById(id int) (*bean.ClusterBean, error)
FindByIdWithoutConfig(id int) (*bean.ClusterBean, error)
FindByIds(id []int) ([]bean.ClusterBean, error)
FindByIdsWithoutConfig(ids []int) ([]*bean.ClusterBean, error)
Update(ctx context.Context, bean *bean.ClusterBean, userId int32) (*bean.ClusterBean, error)
Delete(bean *bean.ClusterBean, userId int32) error

Expand Down Expand Up @@ -355,6 +357,21 @@ func (impl *ClusterServiceImpl) FindByIds(ids []int) ([]bean.ClusterBean, error)
return beans, nil
}

func (impl *ClusterServiceImpl) FindByIdsWithoutConfig(ids []int) ([]*bean.ClusterBean, error) {
models, err := impl.clusterRepository.FindByIds(ids)
if err != nil {
return nil, err
}
var beans []*bean.ClusterBean
for _, model := range models {
bean := adapter.GetClusterBean(model)
//empty bearer token as it will be hidden for user
bean.Config = map[string]string{commonBean.BearerToken: ""}
beans = append(beans, &bean)
}
return beans, nil
}

func (impl *ClusterServiceImpl) Update(ctx context.Context, bean *bean.ClusterBean, userId int32) (*bean.ClusterBean, error) {
model, err := impl.clusterRepository.FindById(bean.Id)
if err != nil {
Expand Down Expand Up @@ -640,13 +657,25 @@ func (impl *ClusterServiceImpl) GetAllClusterNamespaces() map[string][]string {
return result
}

const (
// Cluster connectivity error constants
ErrClusterNotReachable = "cluster is not reachable"
)

func (impl *ClusterServiceImpl) FindAllNamespacesByUserIdAndClusterId(userId int32, clusterId int, isActionUserSuperAdmin bool) ([]string, error) {
result := make([]string, 0)
clusterBean, err := impl.clusterReadService.FindById(clusterId)
if err != nil {
impl.logger.Errorw("failed to find cluster for id", "error", err, "clusterId", clusterId)
return nil, err
}

// Check if cluster has connection errors
if len(clusterBean.ErrorInConnecting) > 0 {
impl.logger.Errorw("cluster is not reachable", "clusterId", clusterId, "clusterName", clusterBean.ClusterName, "error", clusterBean.ErrorInConnecting)
return nil, fmt.Errorf("%s: %s", ErrClusterNotReachable, clusterBean.ErrorInConnecting)
}

namespaceListGroupByCLuster := impl.K8sInformerFactory.GetLatestNamespaceListGroupByCLuster()
namespaces := namespaceListGroupByCLuster[clusterBean.ClusterName]
if len(namespaces) == 0 {
Expand Down
15 changes: 12 additions & 3 deletions pkg/cluster/ClusterServiceExtended.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ package cluster
import (
"context"
"fmt"
"net/http"
"strings"
"time"

"github.com/devtron-labs/common-lib/utils/k8s/commonBean"
"github.com/devtron-labs/devtron/client/argocdServer"
"github.com/devtron-labs/devtron/pkg/cluster/bean"
"github.com/devtron-labs/devtron/pkg/cluster/environment/repository"
"github.com/devtron-labs/devtron/pkg/deployment/gitOps/config"
"net/http"
"strings"
"time"

cluster3 "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster"
"github.com/devtron-labs/devtron/client/grafana"
Expand Down Expand Up @@ -75,6 +76,14 @@ func (impl *ClusterServiceImplExtended) FindAllWithoutConfig() ([]*bean.ClusterB
return beans, nil
}

func (impl *ClusterServiceImplExtended) FindByIdsWithoutConfig(ids []int) ([]*bean.ClusterBean, error) {
beans, err := impl.ClusterServiceImpl.FindByIdsWithoutConfig(ids)
if err != nil {
return nil, err
}
return impl.GetClusterFullModeDTO(beans)
}

func (impl *ClusterServiceImplExtended) GetClusterFullModeDTO(beans []*bean.ClusterBean) ([]*bean.ClusterBean, error) {
//devtron full mode logic
var clusterIds []int
Expand Down
39 changes: 34 additions & 5 deletions pkg/pipeline/workflowStatus/WorkflowStageStatusService.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ package workflowStatus

import (
"encoding/json"
"slices"
"strconv"
"strings"
"time"

"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"
envRepository "github.com/devtron-labs/devtron/pkg/cluster/environment/repository"
"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"
Expand All @@ -16,9 +22,6 @@ import (
"github.com/devtron-labs/devtron/pkg/sql"
"github.com/go-pg/pg"
"go.uber.org/zap"
"slices"
"strings"
"time"
)

type WorkFlowStageStatusService interface {
Expand All @@ -35,6 +38,7 @@ type WorkFlowStageStatusServiceImpl struct {
workflowStatusRepository repository.WorkflowStageRepository
ciWorkflowRepository pipelineConfig.CiWorkflowRepository
cdWorkflowRepository pipelineConfig.CdWorkflowRepository
envRepository envRepository.EnvironmentRepository
transactionManager sql.TransactionWrapper
config *types.CiConfig
}
Expand All @@ -43,13 +47,15 @@ func NewWorkflowStageFlowStatusServiceImpl(logger *zap.SugaredLogger,
workflowStatusRepository repository.WorkflowStageRepository,
ciWorkflowRepository pipelineConfig.CiWorkflowRepository,
cdWorkflowRepository pipelineConfig.CdWorkflowRepository,
envRepository envRepository.EnvironmentRepository,
transactionManager sql.TransactionWrapper,
) *WorkFlowStageStatusServiceImpl {
wfStageServiceImpl := &WorkFlowStageStatusServiceImpl{
logger: logger,
workflowStatusRepository: workflowStatusRepository,
ciWorkflowRepository: ciWorkflowRepository,
cdWorkflowRepository: cdWorkflowRepository,
envRepository: envRepository,
transactionManager: transactionManager,
}
ciConfig, err := types.GetCiConfig()
Expand Down Expand Up @@ -109,9 +115,32 @@ func (impl *WorkFlowStageStatusServiceImpl) updatePodStages(currentWorkflowStage
//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
// add pod name and clusterId in stage metadata if not empty
if len(podName) > 0 {
marshalledMetadata, _ := json.Marshal(map[string]string{"podName": podName})
metadata := map[string]string{"podName": podName}

// Try to get clusterId from the workflow
if stage.WorkflowType == bean.CI_WORKFLOW_TYPE.String() {
// For CI workflows, get clusterId from environment
ciWorkflow, err := impl.ciWorkflowRepository.FindById(stage.WorkflowId)
if err == nil && ciWorkflow.EnvironmentId != 0 {
env, err := impl.envRepository.FindById(ciWorkflow.EnvironmentId)
if err == nil && env != nil && env.Cluster != nil {
metadata["clusterId"] = strconv.Itoa(env.Cluster.Id)
}
}
} else if stage.WorkflowType == bean.CD_WORKFLOW_TYPE_PRE.String() || stage.WorkflowType == bean.CD_WORKFLOW_TYPE_POST.String() || stage.WorkflowType == bean.CD_WORKFLOW_TYPE_DEPLOY.String() {
// For CD workflows, get clusterId from environment
cdWorkflowRunner, err := impl.cdWorkflowRepository.FindWorkflowRunnerById(stage.WorkflowId)
if err == nil && cdWorkflowRunner != nil && cdWorkflowRunner.CdWorkflow != nil && cdWorkflowRunner.CdWorkflow.Pipeline != nil {
env, err := impl.envRepository.FindById(cdWorkflowRunner.CdWorkflow.Pipeline.EnvironmentId)
if err == nil && env != nil && env.Cluster != nil {
metadata["clusterId"] = strconv.Itoa(env.Cluster.Id)
}
}
}

marshalledMetadata, _ := json.Marshal(metadata)
stage.Metadata = string(marshalledMetadata)
}
switch podStatus {
Expand Down
15 changes: 13 additions & 2 deletions specs/cluster_api_spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,24 @@ paths:
required: true
schema:
type: integer
- name: clusterId
in: query
description: comma-separated list of cluster IDs to filter clusters. If not provided, returns all clusters.
required: false
schema:
type: string
example: "1,2,3"
responses:
'200':
description: Successfully get cluster
description: Successfully get cluster(s)
content:
application/json:
schema:
$ref: '#/components/schemas/ClusterBean'
oneOf:
- $ref: '#/components/schemas/ClusterBean'
- type: array
items:
$ref: '#/components/schemas/ClusterBean'
'400':
description: Bad Request. Input Validation(decode) error/wrong request body.
content:
Expand Down
15 changes: 13 additions & 2 deletions specs/swagger/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1832,13 +1832,24 @@ paths:
required: true
schema:
type: integer
- name: clusterId
in: query
description: comma-separated list of cluster IDs to filter clusters. If not provided, returns all clusters.
required: false
schema:
type: string
example: "1,2,3"
responses:
'200':
description: Successfully get cluster
description: Successfully get cluster(s)
content:
application/json:
schema:
$ref: '#/components/schemas/ClusterBean'
oneOf:
- $ref: '#/components/schemas/ClusterBean'
- type: array
items:
$ref: '#/components/schemas/ClusterBean'
'400':
description: Bad Request. Input Validation(decode) error/wrong request body.
content:
Expand Down
4 changes: 2 additions & 2 deletions specs/workflow/workflow-stage-status.internal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ paths:
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"}}]}}'
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":"123","podName":"pod-name"}}]}}'

components:
schemas:
Expand Down Expand Up @@ -89,7 +89,7 @@ components:
metadata:
type: object
properties:
ClusterID:
clusterId:
type: string
description: Cluster ID
podName:
Expand Down
2 changes: 1 addition & 1 deletion wire_gen.go

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

Loading