package rest import ( "encoding/json" "net/http" "os" "github.com/gorilla/mux" "github.com/ocdp/cluster-service/internal/adapter/input/http/dto" "github.com/ocdp/cluster-service/internal/domain/entity" "github.com/ocdp/cluster-service/internal/domain/service" ) // ClusterHandler 集群 Handler type ClusterHandler struct { clusterService *service.ClusterService } // NewClusterHandler 创建集群 Handler func NewClusterHandler(clusterService *service.ClusterService) *ClusterHandler { return &ClusterHandler{ clusterService: clusterService, } } // CreateCluster 创建集群 // @Summary 创建集群 // @Description 创建一个新的 Kubernetes 集群配置 // @Tags Clusters // @Accept json // @Produce json // @Security BearerAuth // @Param request body dto.CreateClusterRequest true "集群信息" // @Success 201 {object} dto.ClusterResponse // @Failure 400 {object} dto.ErrorResponse // @Router /clusters [post] func (h *ClusterHandler) CreateCluster(w http.ResponseWriter, r *http.Request) { var req dto.CreateClusterRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { respondError(w, http.StatusBadRequest, "Invalid request body", err.Error()) return } req.Normalize() // 创建实体 cluster := entity.NewCluster("", "", req.Name, req.Host) cluster.Description = req.Description // 设置认证信息 hasKubeconfig := req.CAData != "" && (len(req.CAData) > 100 && (req.CAData[:11] == "apiVersion:" || req.CAData[:5] == "kind:")) hasCertAuth := req.CertData != "" && req.KeyData != "" if hasKubeconfig { // 使用完整的 kubeconfig 格式 cluster.CAData = req.CAData } else if hasCertAuth { cluster.SetCertAuth(req.CAData, req.CertData, req.KeyData) } else if req.Token != "" { cluster.SetTokenAuth(req.Token) } else if os.Getenv("ADAPTER_MODE") == "mock" { // Mock 模式:如果没有提供认证信息,使用默认的 Mock 证书 cluster.SetCertAuth( "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1vY2sgQ0EgQ2VydGlmaWNhdGUKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==", "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1vY2sgQ2xpZW50IENlcnRpZmljYXRlCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=", "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNb2NrIFByaXZhdGUgS2V5Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0t", ) } else { // 生产模式:没有提供凭证,尝试使用本地 kubeconfig // 不再返回错误,让 TestConnection 尝试使用本地 kubeconfig // cluster 保持空的认证信息,TestConnection 会使用 KUBECONFIG 环境变量 } // 测试集群连接(非 mock 模式下) if os.Getenv("ADAPTER_MODE") != "mock" { if err := h.clusterService.TestConnection(r.Context(), cluster); err != nil { respondError(w, http.StatusBadRequest, "Failed to connect to cluster", err.Error()) return } } // 调用领域服务 if err := h.clusterService.CreateCluster(r.Context(), cluster); err != nil { respondError(w, http.StatusBadRequest, "Failed to create cluster", err.Error()) return } // 返回响应 response := h.toClusterResponse(cluster) respondJSON(w, http.StatusCreated, response) } // GetCluster 获取集群详情 // @Summary 获取集群详情 // @Tags Clusters // @Produce json // @Security BearerAuth // @Param cluster_id path string true "集群 ID" // @Success 200 {object} dto.ClusterResponse // @Failure 404 {object} dto.ErrorResponse // @Router /clusters/{cluster_id} [get] func (h *ClusterHandler) GetCluster(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) clusterID := vars["cluster_id"] cluster, err := h.clusterService.GetCluster(r.Context(), clusterID) if err != nil { respondError(w, http.StatusNotFound, "Cluster not found", err.Error()) return } response := h.toClusterResponse(cluster) respondJSON(w, http.StatusOK, response) } // GetAllClusters 获取所有集群 // @Summary 列出所有集群 // @Tags Clusters // @Produce json // @Security BearerAuth // @Success 200 {array} dto.ClusterResponse // @Failure 500 {object} dto.ErrorResponse // @Router /clusters [get] func (h *ClusterHandler) GetAllClusters(w http.ResponseWriter, r *http.Request) { clusters, err := h.clusterService.ListClusters(r.Context()) if err != nil { respondError(w, http.StatusInternalServerError, "Failed to list clusters", err.Error()) return } responses := make([]*dto.ClusterResponse, 0, len(clusters)) for _, cluster := range clusters { responses = append(responses, h.toClusterResponse(cluster)) } respondJSON(w, http.StatusOK, responses) } // UpdateCluster 更新集群 // @Summary 更新集群 // @Tags Clusters // @Accept json // @Produce json // @Security BearerAuth // @Param cluster_id path string true "集群 ID" // @Param request body dto.UpdateClusterRequest true "更新内容" // @Success 200 {object} dto.ClusterResponse // @Failure 404 {object} dto.ErrorResponse // @Router /clusters/{cluster_id} [put] func (h *ClusterHandler) UpdateCluster(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) clusterID := vars["cluster_id"] var req dto.UpdateClusterRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { respondError(w, http.StatusBadRequest, "Invalid request body", err.Error()) return } req.Normalize() // 获取现有集群 cluster, err := h.clusterService.GetCluster(r.Context(), clusterID) if err != nil { respondError(w, http.StatusNotFound, "Cluster not found", err.Error()) return } // 更新字段 cluster.Update(req.Name, req.Host, req.Description) if req.CertData != "" && req.KeyData != "" { cluster.SetCertAuth(req.CAData, req.CertData, req.KeyData) } else if req.Token != "" { cluster.SetTokenAuth(req.Token) } // 调用领域服务 if err := h.clusterService.UpdateCluster(r.Context(), cluster); err != nil { respondError(w, http.StatusBadRequest, "Failed to update cluster", err.Error()) return } response := h.toClusterResponse(cluster) respondJSON(w, http.StatusOK, response) } // DeleteCluster 删除集群 // @Summary 删除集群 // @Tags Clusters // @Produce json // @Security BearerAuth // @Param cluster_id path string true "集群 ID" // @Success 204 {string} string "No Content" // @Failure 404 {object} dto.ErrorResponse // @Router /clusters/{cluster_id} [delete] func (h *ClusterHandler) DeleteCluster(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) clusterID := vars["cluster_id"] if err := h.clusterService.DeleteCluster(r.Context(), clusterID); err != nil { respondError(w, http.StatusNotFound, "Failed to delete cluster", err.Error()) return } w.WriteHeader(http.StatusNoContent) } // GetClusterHealth 获取集群健康状态 // @Summary 获取集群健康状态 // @Tags Clusters // @Produce json // @Security BearerAuth // @Param cluster_id path string true "集群 ID" // @Success 200 {object} dto.ClusterHealthResponse // @Failure 404 {object} dto.ErrorResponse // @Router /clusters/{cluster_id}/health [get] func (h *ClusterHandler) GetClusterHealth(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) clusterID := vars["cluster_id"] // 获取集群 cluster, err := h.clusterService.GetCluster(r.Context(), clusterID) if err != nil { respondError(w, http.StatusNotFound, "Cluster not found", err.Error()) return } // 测试连接 err = h.clusterService.TestConnection(r.Context(), cluster) response := &dto.ClusterHealthResponse{ Healthy: err == nil, } if err != nil { response.Message = err.Error() } else { response.Message = "Cluster is healthy" } respondJSON(w, http.StatusOK, response) } // toClusterResponse 将 Cluster 实体转换为响应 DTO(脱敏) func (h *ClusterHandler) toClusterResponse(cluster *entity.Cluster) *dto.ClusterResponse { return dto.ToClusterResponse(cluster) }