- Add Workspace domain (entity, repository, service, handler, DTO) - Add multi-tenant K8s client with tenant binding and quota management - Add K8s diagnostics client (instance diagnostics) - Add authorization middleware (authz package) - Restructure frontend to feature-based architecture (features/) - Add User Management page in configuration - Add AccessDenied page and route guards - Refactor shared components (form inputs, layout, UI) - Update Tailwind config for new design system - Add comprehensive documentation (docs/, tasks/, plans) - Improve cluster service with better kubeconfig handling - Add tests for crypto, config, helm client, tenant binding
212 lines
6.3 KiB
Go
212 lines
6.3 KiB
Go
package rest
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"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"
|
|
)
|
|
|
|
// RegistryHandler Registry Handler
|
|
type RegistryHandler struct {
|
|
registryService *service.RegistryService
|
|
}
|
|
|
|
// NewRegistryHandler 创建 Registry Handler
|
|
func NewRegistryHandler(registryService *service.RegistryService) *RegistryHandler {
|
|
return &RegistryHandler{
|
|
registryService: registryService,
|
|
}
|
|
}
|
|
|
|
// CreateRegistry 创建 Registry
|
|
// @Summary 创建 Registry
|
|
// @Description 新增 OCI Registry 配置
|
|
// @Tags Registries
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param request body dto.CreateRegistryRequest true "Registry 信息"
|
|
// @Success 201 {object} dto.RegistryResponse
|
|
// @Failure 400 {object} dto.ErrorResponse
|
|
// @Router /registries [post]
|
|
func (h *RegistryHandler) CreateRegistry(w http.ResponseWriter, r *http.Request) {
|
|
var req dto.CreateRegistryRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
respondError(w, http.StatusBadRequest, "Invalid request body", err.Error())
|
|
return
|
|
}
|
|
|
|
// 创建实体
|
|
registry := entity.NewRegistry(req.Name, req.URL)
|
|
registry.Description = req.Description
|
|
registry.Insecure = req.Insecure
|
|
registry.Visibility = req.Visibility
|
|
if req.GlobalShared || req.GlobalSharedAlt {
|
|
registry.Visibility = "global_shared"
|
|
}
|
|
registry.SetCredentials(req.Username, req.Password)
|
|
|
|
// 调用领域服务
|
|
if err := h.registryService.CreateRegistry(r.Context(), registry); err != nil {
|
|
respondError(w, http.StatusBadRequest, "Failed to create registry", err.Error())
|
|
return
|
|
}
|
|
|
|
// 返回响应(脱敏)
|
|
response := dto.ToRegistryResponse(registry)
|
|
respondJSON(w, http.StatusCreated, response)
|
|
}
|
|
|
|
// GetRegistry 获取 Registry 详情
|
|
// @Summary 获取 Registry
|
|
// @Tags Registries
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param registry_id path string true "Registry ID"
|
|
// @Success 200 {object} dto.RegistryResponse
|
|
// @Failure 404 {object} dto.ErrorResponse
|
|
// @Router /registries/{registry_id} [get]
|
|
func (h *RegistryHandler) GetRegistry(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
registryID := vars["registry_id"]
|
|
|
|
registry, err := h.registryService.GetRegistry(r.Context(), registryID)
|
|
if err != nil {
|
|
respondError(w, http.StatusNotFound, "Registry not found", err.Error())
|
|
return
|
|
}
|
|
|
|
// 返回响应(脱敏)
|
|
response := dto.ToRegistryResponse(registry)
|
|
respondJSON(w, http.StatusOK, response)
|
|
}
|
|
|
|
// GetAllRegistries 获取所有 Registries
|
|
// @Summary 列出所有 Registries
|
|
// @Tags Registries
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Success 200 {array} dto.RegistryResponse
|
|
// @Failure 500 {object} dto.ErrorResponse
|
|
// @Router /registries [get]
|
|
func (h *RegistryHandler) GetAllRegistries(w http.ResponseWriter, r *http.Request) {
|
|
registries, err := h.registryService.ListRegistries(r.Context())
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, "Failed to list registries", err.Error())
|
|
return
|
|
}
|
|
|
|
// 转换为响应(脱敏)
|
|
responses := make([]*dto.RegistryResponse, 0, len(registries))
|
|
for _, registry := range registries {
|
|
responses = append(responses, dto.ToRegistryResponse(registry))
|
|
}
|
|
|
|
respondJSON(w, http.StatusOK, responses)
|
|
}
|
|
|
|
// UpdateRegistry 更新 Registry
|
|
// @Summary 更新 Registry
|
|
// @Tags Registries
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param registry_id path string true "Registry ID"
|
|
// @Param request body dto.UpdateRegistryRequest true "更新内容"
|
|
// @Success 200 {object} dto.RegistryResponse
|
|
// @Failure 404 {object} dto.ErrorResponse
|
|
// @Router /registries/{registry_id} [put]
|
|
func (h *RegistryHandler) UpdateRegistry(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
registryID := vars["registry_id"]
|
|
|
|
var req dto.UpdateRegistryRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
respondError(w, http.StatusBadRequest, "Invalid request body", err.Error())
|
|
return
|
|
}
|
|
|
|
// 获取现有 Registry
|
|
registry, err := h.registryService.GetRegistry(r.Context(), registryID)
|
|
if err != nil {
|
|
respondError(w, http.StatusNotFound, "Registry not found", err.Error())
|
|
return
|
|
}
|
|
|
|
// 更新字段
|
|
registry.Update(req.Name, req.URL, req.Description)
|
|
registry.Insecure = req.Insecure
|
|
if req.Visibility != "" {
|
|
registry.Visibility = req.Visibility
|
|
}
|
|
if req.GlobalShared || req.GlobalSharedAlt {
|
|
registry.Visibility = "global_shared"
|
|
}
|
|
if req.Username != "" || req.Password != "" {
|
|
registry.SetCredentials(req.Username, req.Password)
|
|
}
|
|
|
|
// 调用领域服务
|
|
if err := h.registryService.UpdateRegistry(r.Context(), registry); err != nil {
|
|
respondError(w, http.StatusBadRequest, "Failed to update registry", err.Error())
|
|
return
|
|
}
|
|
|
|
// 返回响应(脱敏)
|
|
response := dto.ToRegistryResponse(registry)
|
|
respondJSON(w, http.StatusOK, response)
|
|
}
|
|
|
|
// DeleteRegistry 删除 Registry
|
|
// @Summary 删除 Registry
|
|
// @Tags Registries
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param registry_id path string true "Registry ID"
|
|
// @Success 204 {string} string "No Content"
|
|
// @Failure 404 {object} dto.ErrorResponse
|
|
// @Router /registries/{registry_id} [delete]
|
|
func (h *RegistryHandler) DeleteRegistry(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
registryID := vars["registry_id"]
|
|
|
|
if err := h.registryService.DeleteRegistry(r.Context(), registryID); err != nil {
|
|
respondError(w, http.StatusNotFound, "Failed to delete registry", err.Error())
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// GetRegistryHealth 获取 Registry 健康状态
|
|
// @Summary 检查 Registry 健康
|
|
// @Tags Registries
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param registry_id path string true "Registry ID"
|
|
// @Success 200 {object} dto.RegistryHealthResponse
|
|
// @Router /registries/{registry_id}/health [get]
|
|
func (h *RegistryHandler) GetRegistryHealth(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
registryID := vars["registry_id"]
|
|
|
|
// 调用领域服务检查健康状态
|
|
err := h.registryService.CheckHealth(r.Context(), registryID)
|
|
|
|
response := &dto.RegistryHealthResponse{
|
|
Healthy: err == nil,
|
|
}
|
|
|
|
if err != nil {
|
|
response.Message = err.Error()
|
|
} else {
|
|
response.Message = "Registry is healthy"
|
|
}
|
|
|
|
respondJSON(w, http.StatusOK, response)
|
|
}
|