package handlers import ( "fmt" "gorm.io/gorm" "strconv" "time" "ezops/internal/models" k8sclient "ezops/pkg/kubernetesclient" "github.com/gin-gonic/gin" ) // KubernetesHandler K8s处理器 type KubernetesHandler struct { db *gorm.DB } // NewKubernetesHandler 创建K8s处理器 func NewKubernetesHandler(db *gorm.DB) *KubernetesHandler { return &KubernetesHandler{db: db} } // ============================================================================ // Shared helpers (used by all k8s_*.go files in this package) // ============================================================================ func (h *KubernetesHandler) resolveClusterCode(code string) int { if code == "" { return 0 } var cluster models.KubernetesCluster if err := h.db.Where("code = ?", code).First(&cluster).Error; err != nil { return 0 } return int(cluster.ID) } // formatAge converts a K8s creationTimestamp (RFC3339) to a human-readable relative age func formatAge(creationTimestamp string) string { if creationTimestamp == "" { return "-" } t, err := time.Parse(time.RFC3339, creationTimestamp) if err != nil { return creationTimestamp } d := time.Since(t) switch { case d < time.Minute: return fmt.Sprintf("%ds", int(d.Seconds())) case d < time.Hour: return fmt.Sprintf("%dm", int(d.Minutes())) case d < 24*time.Hour: return fmt.Sprintf("%dh", int(d.Hours())) case d < 30*24*time.Hour: return fmt.Sprintf("%dd", int(d.Hours()/24)) case d < 365*24*time.Hour: return fmt.Sprintf("%dM", int(d.Hours()/(24*30))) default: return fmt.Sprintf("%dy", int(d.Hours()/(24*365))) } } // getK8sClientByCode resolves cluster by code, falls back to ID func (h *KubernetesHandler) getK8sClientByCode(c *gin.Context) (*k8sclient.Client, *models.KubernetesCluster, error) { clusterID, _ := strconv.Atoi(c.Param("id")) if clusterID == 0 { // 支持 :clusterCode 或 :id 参数 code := c.Param("clusterCode") if code == "" { code = c.Param("id") } clusterID = h.resolveClusterCode(code) } if clusterID == 0 { return nil, nil, fmt.Errorf("cluster not found") } return h.getK8sClient(clusterID) } // ============================================================================ // NS wrappers — read namespace from path (Kuboard-style routes) // ============================================================================ func (h *KubernetesHandler) getK8sClient(clusterID int) (*k8sclient.Client, *models.KubernetesCluster, error) { var cluster models.KubernetesCluster if err := h.db.First(&cluster, clusterID).Error; err != nil { return nil, nil, fmt.Errorf("cluster not found") } if cluster.KubeConfig == "" { return nil, nil, fmt.Errorf("no kubeconfig") } client, err := k8sclient.NewClient(cluster.KubeConfig) if err != nil { return nil, nil, err } return client, &cluster, nil } // ============================================================================ // PVC (存储) handlers // ============================================================================ // ListPVCsNS lists PersistentVolumeClaims in a namespace (code-based)