refactor: 全局重命名 k8s → kubernetes (前后端+路由+表名+文件)
后端: - pkg/k8sclient → pkg/kubernetesclient - models/k8s.go → models/kubernetes.go - handlers/k8s.go → handlers/kubernetes.go - K8sCluster/K8sNode/.. → KubernetesCluster/KubernetesNode/.. - K8sHandler → KubernetesHandler - 路由: /k8s-clusters → /kubernetes-clusters - 路由: /k8s/:code/namespace/:ns/... → /kubernetes/:code/namespace/:ns/... (Kuboard风格) - 表前缀: container_k8s_ → container_kubernetes_ 前端: - components/k8s/ → components/kubernetes/ - K8sClusters → KubernetesClusters - K8sWorkloads → KubernetesWorkloads - K8sNodes → KubernetesNodes - k8sApi → kubernetesApi - 路由前缀: /k8s/ → /kubernetes/ 测试验证: ✅ /kubernetes/k8s-cluster-liren/namespace/kube-system/deployments → 3 items ✅ /kubernetes/k8s-cluster-liren/namespace/kube-system/pods → 7 items ✅ /kubernetes/k8s-cluster-liren/namespace/kube-system/services → 4 items ✅ /kubernetes/k8s-cluster-liren/namespace/kube-system/configmaps → 6 items ✅ /kubernetes/k8s-cluster-liren/namespace/kube-system/secrets → 1 item ✅ /kubernetes/k8s-cluster-liren/namespaces → 4 items
This commit is contained in:
1 parent
f7b667b878
commit
cac1414917
27 files changed
+779
-284
No files matched your search
@@ -134,7 +134,7 @@ func (h *AuditHandler) GetAuditModules(c *gin.Context) {
|
||||
modules := []map[string]string{
|
||||
{"value": "user", "label": "用户管理"},
|
||||
{"value": "server", "label": "服务器管理"},
|
||||
{"value": "k8s", "label": "Kubernetes"},
|
||||
{"value": "kubernetes", "label": "Kubernetes"},
|
||||
{"value": "alert", "label": "监控告警"},
|
||||
{"value": "pipeline", "label": "应用发布"},
|
||||
{"value": "automation", "label": "自动化运维"},
|
||||
|
||||
@@ -53,16 +53,16 @@ func (h *DashboardHandler) GetStats(c *gin.Context) {
|
||||
stats.ServerStats = serverStats
|
||||
|
||||
// K8s集群统计
|
||||
var k8sStats models.K8sClusterStats
|
||||
h.db.Model(&models.K8sCluster{}).Count(&k8sStats.Total)
|
||||
h.db.Model(&models.K8sCluster{}).Where("status = ?", "healthy").Count(&k8sStats.Healthy)
|
||||
h.db.Model(&models.K8sCluster{}).Where("status = ?", "warning").Count(&k8sStats.Warning)
|
||||
h.db.Model(&models.K8sCluster{}).Where("status = ?", "error").Count(&k8sStats.Error)
|
||||
var k8sStats models.KubernetesClusterStats
|
||||
h.db.Model(&models.KubernetesCluster{}).Count(&k8sStats.Total)
|
||||
h.db.Model(&models.KubernetesCluster{}).Where("status = ?", "healthy").Count(&k8sStats.Healthy)
|
||||
h.db.Model(&models.KubernetesCluster{}).Where("status = ?", "warning").Count(&k8sStats.Warning)
|
||||
h.db.Model(&models.KubernetesCluster{}).Where("status = ?", "error").Count(&k8sStats.Error)
|
||||
|
||||
var totalNodes, totalPods, totalServices int64
|
||||
h.db.Model(&models.K8sNode{}).Count(&totalNodes)
|
||||
h.db.Model(&models.K8sPod{}).Count(&totalPods)
|
||||
h.db.Model(&models.K8sService{}).Count(&totalServices)
|
||||
h.db.Model(&models.KubernetesNode{}).Count(&totalNodes)
|
||||
h.db.Model(&models.KubernetesPod{}).Count(&totalPods)
|
||||
h.db.Model(&models.KubernetesService{}).Count(&totalServices)
|
||||
k8sStats.TotalNodes = totalNodes
|
||||
k8sStats.TotalPods = totalPods
|
||||
k8sStats.TotalServices = totalServices
|
||||
|
||||
+429
-76
@@ -11,20 +11,20 @@ import (
|
||||
"time"
|
||||
|
||||
"ezops/internal/models"
|
||||
"ezops/pkg/k8sclient"
|
||||
"ezops/pkg/kubernetesclient"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// K8sHandler K8s处理器
|
||||
type K8sHandler struct {
|
||||
// KubernetesHandler K8s处理器
|
||||
type KubernetesHandler struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewK8sHandler 创建K8s处理器
|
||||
func NewK8sHandler(db *gorm.DB) *K8sHandler {
|
||||
return &K8sHandler{db: db}
|
||||
// NewKubernetesHandler 创建K8s处理器
|
||||
func NewKubernetesHandler(db *gorm.DB) *KubernetesHandler {
|
||||
return &KubernetesHandler{db: db}
|
||||
}
|
||||
|
||||
// ListClusters 获取集群列表
|
||||
@@ -36,15 +36,15 @@ func NewK8sHandler(db *gorm.DB) *K8sHandler {
|
||||
// @Param page query int false "页码"
|
||||
// @Param page_size query int false "每页数量"
|
||||
// @Success 200 {object} models.Response{data=models.ListResponse}
|
||||
// @Router /k8s-clusters [get]
|
||||
func (h *K8sHandler) ListClusters(c *gin.Context) {
|
||||
// @Router /kubernetes-clusters [get]
|
||||
func (h *KubernetesHandler) ListClusters(c *gin.Context) {
|
||||
var query models.PageQuery
|
||||
c.ShouldBindQuery(&query)
|
||||
|
||||
var total int64
|
||||
h.db.Model(&models.K8sCluster{}).Count(&total)
|
||||
h.db.Model(&models.KubernetesCluster{}).Count(&total)
|
||||
|
||||
var clusters []models.K8sCluster
|
||||
var clusters []models.KubernetesCluster
|
||||
h.db.Offset(query.GetOffset()).Limit(query.GetLimit()).Find(&clusters)
|
||||
|
||||
c.JSON(http.StatusOK, models.Response{
|
||||
@@ -64,12 +64,12 @@ func (h *K8sHandler) ListClusters(c *gin.Context) {
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path int true "集群ID"
|
||||
// @Success 200 {object} models.Response{data=models.K8sCluster}
|
||||
// @Router /k8s-clusters/{id} [get]
|
||||
func (h *K8sHandler) GetCluster(c *gin.Context) {
|
||||
// @Success 200 {object} models.Response{data=models.KubernetesCluster}
|
||||
// @Router /kubernetes-clusters/{id} [get]
|
||||
func (h *KubernetesHandler) GetCluster(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
var cluster models.K8sCluster
|
||||
var cluster models.KubernetesCluster
|
||||
if err := h.db.First(&cluster, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, models.Response{
|
||||
Code: 404,
|
||||
@@ -92,11 +92,11 @@ func (h *K8sHandler) GetCluster(c *gin.Context) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body models.CreateK8sClusterRequest true "创建请求"
|
||||
// @Success 200 {object} models.Response{data=models.K8sCluster}
|
||||
// @Router /k8s-clusters [post]
|
||||
func (h *K8sHandler) CreateCluster(c *gin.Context) {
|
||||
var req models.CreateK8sClusterRequest
|
||||
// @Param request body models.CreateKubernetesClusterRequest true "创建请求"
|
||||
// @Success 200 {object} models.Response{data=models.KubernetesCluster}
|
||||
// @Router /kubernetes-clusters [post]
|
||||
func (h *KubernetesHandler) CreateCluster(c *gin.Context) {
|
||||
var req models.CreateKubernetesClusterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, models.Response{
|
||||
Code: 400,
|
||||
@@ -105,7 +105,7 @@ func (h *K8sHandler) CreateCluster(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
cluster := models.K8sCluster{
|
||||
cluster := models.KubernetesCluster{
|
||||
Name: req.Name,
|
||||
Code: req.Code,
|
||||
Version: req.Version,
|
||||
@@ -141,10 +141,10 @@ func (h *K8sHandler) CreateCluster(c *gin.Context) {
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path int true "集群ID"
|
||||
// @Param request body models.CreateK8sClusterRequest true "更新请求"
|
||||
// @Success 200 {object} models.Response{data=models.K8sCluster}
|
||||
// @Router /k8s-clusters/{id} [put]
|
||||
func (h *K8sHandler) UpdateCluster(c *gin.Context) {
|
||||
// @Param request body models.CreateKubernetesClusterRequest true "更新请求"
|
||||
// @Success 200 {object} models.Response{data=models.KubernetesCluster}
|
||||
// @Router /kubernetes-clusters/{id} [put]
|
||||
func (h *KubernetesHandler) UpdateCluster(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
// 用 map 接收,避免 binding:"required" 校验 // Logan.Li
|
||||
@@ -157,7 +157,7 @@ func (h *K8sHandler) UpdateCluster(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var cluster models.K8sCluster
|
||||
var cluster models.KubernetesCluster
|
||||
if err := h.db.First(&cluster, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, models.Response{
|
||||
Code: 404,
|
||||
@@ -219,10 +219,10 @@ func (h *K8sHandler) UpdateCluster(c *gin.Context) {
|
||||
}
|
||||
|
||||
// GetClusterDetail 返回集群完整信息(含 token/kube_config,供编辑回填) // Logan.Li
|
||||
func (h *K8sHandler) GetClusterDetail(c *gin.Context) {
|
||||
func (h *KubernetesHandler) GetClusterDetail(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
var cluster models.K8sCluster
|
||||
var cluster models.KubernetesCluster
|
||||
if err := h.db.First(&cluster, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, models.Response{
|
||||
Code: 404,
|
||||
@@ -264,11 +264,11 @@ func (h *K8sHandler) GetClusterDetail(c *gin.Context) {
|
||||
// @Security Bearer
|
||||
// @Param id path int true "集群ID"
|
||||
// @Success 200 {object} models.Response
|
||||
// @Router /k8s-clusters/{id} [delete]
|
||||
func (h *K8sHandler) DeleteCluster(c *gin.Context) {
|
||||
// @Router /kubernetes-clusters/{id} [delete]
|
||||
func (h *KubernetesHandler) DeleteCluster(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
if err := h.db.Delete(&models.K8sCluster{}, id).Error; err != nil {
|
||||
if err := h.db.Delete(&models.KubernetesCluster{}, id).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, models.Response{
|
||||
Code: 500,
|
||||
Message: "删除失败",
|
||||
@@ -289,9 +289,9 @@ func (h *K8sHandler) DeleteCluster(c *gin.Context) {
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path int true "集群ID"
|
||||
// @Success 200 {object} models.Response{data=[]models.K8sNode}
|
||||
// @Router /k8s-clusters/{id}/nodes [get]
|
||||
func (h *K8sHandler) ListNodes(c *gin.Context) {
|
||||
// @Success 200 {object} models.Response{data=[]models.KubernetesNode}
|
||||
// @Router /kubernetes-clusters/{id}/nodes [get]
|
||||
func (h *KubernetesHandler) ListNodes(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
@@ -363,9 +363,9 @@ func (h *K8sHandler) ListNodes(c *gin.Context) {
|
||||
// @Security Bearer
|
||||
// @Param id path int true "集群ID"
|
||||
// @Param namespace query string false "命名空间"
|
||||
// @Success 200 {object} models.Response{data=[]models.K8sPod}
|
||||
// @Router /k8s-clusters/{id}/pods [get]
|
||||
func (h *K8sHandler) ListPods(c *gin.Context) {
|
||||
// @Success 200 {object} models.Response{data=[]models.KubernetesPod}
|
||||
// @Router /kubernetes-clusters/{id}/pods [get]
|
||||
func (h *KubernetesHandler) ListPods(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Query("namespace")
|
||||
|
||||
@@ -423,9 +423,9 @@ func (h *K8sHandler) ListPods(c *gin.Context) {
|
||||
// @Security Bearer
|
||||
// @Param id path int true "集群ID"
|
||||
// @Param namespace query string false "命名空间"
|
||||
// @Success 200 {object} models.Response{data=[]models.K8sDeployment}
|
||||
// @Router /k8s-clusters/{id}/deployments [get]
|
||||
func (h *K8sHandler) ListDeployments(c *gin.Context) {
|
||||
// @Success 200 {object} models.Response{data=[]models.KubernetesDeployment}
|
||||
// @Router /kubernetes-clusters/{id}/deployments [get]
|
||||
func (h *KubernetesHandler) ListDeployments(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Query("namespace")
|
||||
|
||||
@@ -477,9 +477,9 @@ func (h *K8sHandler) ListDeployments(c *gin.Context) {
|
||||
// @Security Bearer
|
||||
// @Param id path int true "集群ID"
|
||||
// @Param namespace query string false "命名空间"
|
||||
// @Success 200 {object} models.Response{data=[]models.K8sService}
|
||||
// @Router /k8s-clusters/{id}/services [get]
|
||||
func (h *K8sHandler) ListServices(c *gin.Context) {
|
||||
// @Success 200 {object} models.Response{data=[]models.KubernetesService}
|
||||
// @Router /kubernetes-clusters/{id}/services [get]
|
||||
func (h *KubernetesHandler) ListServices(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Query("namespace")
|
||||
|
||||
@@ -525,9 +525,9 @@ func (h *K8sHandler) ListServices(c *gin.Context) {
|
||||
// @Security Bearer
|
||||
// @Param id path int true "集群ID"
|
||||
// @Param namespace query string false "命名空间"
|
||||
// @Success 200 {object} models.Response{data=[]models.K8sIngress}
|
||||
// @Router /k8s-clusters/{id}/ingresses [get]
|
||||
func (h *K8sHandler) ListIngresses(c *gin.Context) {
|
||||
// @Success 200 {object} models.Response{data=[]models.KubernetesIngress}
|
||||
// @Router /kubernetes-clusters/{id}/ingresses [get]
|
||||
func (h *KubernetesHandler) ListIngresses(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Query("namespace")
|
||||
|
||||
@@ -570,7 +570,7 @@ func (h *K8sHandler) ListIngresses(c *gin.Context) {
|
||||
}
|
||||
|
||||
// GetTopology 获取集群拓扑布局 // Logan.Li
|
||||
func (h *K8sHandler) GetTopology(c *gin.Context) {
|
||||
func (h *KubernetesHandler) GetTopology(c *gin.Context) {
|
||||
clusterID := c.Param("id")
|
||||
var layout models.TopologyLayout
|
||||
result := h.db.Where("cluster_id = ?", clusterID).First(&layout)
|
||||
@@ -582,7 +582,7 @@ func (h *K8sHandler) GetTopology(c *gin.Context) {
|
||||
}
|
||||
|
||||
// SaveTopology 保存集群拓扑布局 // Logan.Li
|
||||
func (h *K8sHandler) SaveTopology(c *gin.Context) {
|
||||
func (h *KubernetesHandler) SaveTopology(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
var req struct {
|
||||
LayoutData string `json:"layout_data"`
|
||||
@@ -607,10 +607,10 @@ func (h *K8sHandler) SaveTopology(c *gin.Context) {
|
||||
|
||||
|
||||
// SyncCluster 同步集群资源(连接真实K8s API拉取数据)
|
||||
func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
func (h *KubernetesHandler) SyncCluster(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
var cluster models.K8sCluster
|
||||
var cluster models.KubernetesCluster
|
||||
if err := h.db.First(&cluster, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "集群不存在"})
|
||||
return
|
||||
@@ -632,7 +632,7 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
// Sync nodes
|
||||
if nodes, err := client.ListNodes(); err == nil {
|
||||
// Use raw SQL for reliability (avoid GORM soft-delete / auto-timestamp issues)
|
||||
h.db.Exec("DELETE FROM k8s_nodes WHERE cluster_id = ?", cluster.ID)
|
||||
h.db.Exec("DELETE FROM kubernetes_nodes WHERE cluster_id = ?", cluster.ID)
|
||||
for _, n := range nodes.Items {
|
||||
role := "worker"
|
||||
if _, ok := n.Metadata.Labels["node-role.kubernetes.io/master"]; ok {
|
||||
@@ -656,7 +656,7 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
}
|
||||
labelsJSON, _ := json.Marshal(n.Metadata.Labels)
|
||||
now := time.Now()
|
||||
err2 := h.db.Exec(`INSERT INTO k8s_nodes (cluster_id, name, ip, role, status, os, kubelet_version, cpu, memory, max_pods, labels, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
err2 := h.db.Exec(`INSERT INTO kubernetes_nodes (cluster_id, name, ip, role, status, os, kubelet_version, cpu, memory, max_pods, labels, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
cluster.ID, n.Metadata.Name, ip, role, nodeStatus, n.Status.NodeInfo.OSImage, n.Status.NodeInfo.KubeletVersion,
|
||||
parseIntResource(n.Status.Capacity["cpu"]), parseMemResource(n.Status.Capacity["memory"]), parseIntResource(n.Status.Capacity["pods"]),
|
||||
string(labelsJSON), now, now).Error
|
||||
@@ -672,7 +672,7 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
|
||||
// Sync pods
|
||||
if pods, err := client.ListPods(); err == nil {
|
||||
h.db.Where("cluster_id = ?", cluster.ID).Delete(&models.K8sPod{})
|
||||
h.db.Where("cluster_id = ?", cluster.ID).Delete(&models.KubernetesPod{})
|
||||
for _, p := range pods.Items {
|
||||
image := ""
|
||||
if len(p.Spec.Containers) > 0 {
|
||||
@@ -683,7 +683,7 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
restarts = p.Status.ContainerStatuses[0].RestartCount
|
||||
}
|
||||
labelsJSON, _ := json.Marshal(p.Metadata.Labels)
|
||||
h.db.Create(&models.K8sPod{
|
||||
h.db.Create(&models.KubernetesPod{
|
||||
ClusterID: cluster.ID,
|
||||
Namespace: p.Metadata.Namespace,
|
||||
Name: p.Metadata.Name,
|
||||
@@ -702,14 +702,14 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
|
||||
// Sync deployments
|
||||
if deps, err := client.ListDeployments(); err == nil {
|
||||
h.db.Where("cluster_id = ?", cluster.ID).Delete(&models.K8sDeployment{})
|
||||
h.db.Where("cluster_id = ?", cluster.ID).Delete(&models.KubernetesDeployment{})
|
||||
for _, d := range deps.Items {
|
||||
image := ""
|
||||
if len(d.Spec.Template.Spec.Containers) > 0 {
|
||||
image = d.Spec.Template.Spec.Containers[0].Image
|
||||
}
|
||||
labelsJSON, _ := json.Marshal(d.Metadata.Labels)
|
||||
h.db.Create(&models.K8sDeployment{
|
||||
h.db.Create(&models.KubernetesDeployment{
|
||||
ClusterID: cluster.ID,
|
||||
Namespace: d.Metadata.Namespace,
|
||||
Name: d.Metadata.Name,
|
||||
@@ -727,12 +727,12 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
|
||||
// Sync services
|
||||
if svcs, err := client.ListServices(); err == nil {
|
||||
h.db.Where("cluster_id = ?", cluster.ID).Delete(&models.K8sService{})
|
||||
h.db.Where("cluster_id = ?", cluster.ID).Delete(&models.KubernetesService{})
|
||||
for _, s := range svcs.Items {
|
||||
portsJSON, _ := json.Marshal(s.Spec.Ports)
|
||||
selectorJSON, _ := json.Marshal(s.Spec.Selector)
|
||||
labelsJSON, _ := json.Marshal(s.Metadata.Labels)
|
||||
h.db.Create(&models.K8sService{
|
||||
h.db.Create(&models.KubernetesService{
|
||||
ClusterID: cluster.ID,
|
||||
Namespace: s.Metadata.Namespace,
|
||||
Name: s.Metadata.Name,
|
||||
@@ -748,7 +748,7 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
|
||||
// Sync ingresses
|
||||
if ings, err := client.ListIngresses(); err == nil {
|
||||
h.db.Where("cluster_id = ?", cluster.ID).Delete(&models.K8sIngress{})
|
||||
h.db.Where("cluster_id = ?", cluster.ID).Delete(&models.KubernetesIngress{})
|
||||
for _, ing := range ings.Items {
|
||||
hosts := []string{}
|
||||
for _, rule := range ing.Spec.Rules {
|
||||
@@ -764,7 +764,7 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
}
|
||||
tlsHostsJSON, _ := json.Marshal(tlsHosts)
|
||||
labelsJSON, _ := json.Marshal(ing.Metadata.Labels)
|
||||
h.db.Create(&models.K8sIngress{
|
||||
h.db.Create(&models.KubernetesIngress{
|
||||
ClusterID: cluster.ID,
|
||||
Namespace: ing.Metadata.Namespace,
|
||||
Name: ing.Metadata.Name,
|
||||
@@ -800,7 +800,7 @@ func (h *K8sHandler) SyncCluster(c *gin.Context) {
|
||||
// ============================================================================
|
||||
|
||||
// GetPodLogs 获取 Pod 日志(支持 stream=true 实时流)
|
||||
func (h *K8sHandler) GetPodLogs(c *gin.Context) {
|
||||
func (h *KubernetesHandler) GetPodLogs(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
podName := c.Param("podName")
|
||||
@@ -857,7 +857,7 @@ func (h *K8sHandler) GetPodLogs(c *gin.Context) {
|
||||
// ============================================================================
|
||||
|
||||
// ExecTerminal WebSocket 终端 — 前端 WS → 后端 → K8s SPDY exec
|
||||
func (h *K8sHandler) ExecTerminal(c *gin.Context) {
|
||||
func (h *KubernetesHandler) ExecTerminal(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
podName := c.Param("podName")
|
||||
@@ -970,7 +970,7 @@ func (h *K8sHandler) ExecTerminal(c *gin.Context) {
|
||||
// ============================================================================
|
||||
|
||||
// ExecInPod 在 Pod 中执行命令 (文件浏览 / 单次命令)
|
||||
func (h *K8sHandler) ExecInPod(c *gin.Context) {
|
||||
func (h *KubernetesHandler) ExecInPod(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
podName := c.Param("podName")
|
||||
@@ -1008,7 +1008,7 @@ func (h *K8sHandler) ExecInPod(c *gin.Context) {
|
||||
// ============================================================================
|
||||
|
||||
// ScaleDeployment 缩放 Deployment 副本数
|
||||
func (h *K8sHandler) ScaleDeployment(c *gin.Context) {
|
||||
func (h *KubernetesHandler) ScaleDeployment(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
name := c.Param("name")
|
||||
@@ -1040,7 +1040,7 @@ func (h *K8sHandler) ScaleDeployment(c *gin.Context) {
|
||||
}
|
||||
|
||||
// RestartDeployment 重启 Deployment (滚动重启)
|
||||
func (h *K8sHandler) RestartDeployment(c *gin.Context) {
|
||||
func (h *KubernetesHandler) RestartDeployment(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
name := c.Param("name")
|
||||
@@ -1064,7 +1064,7 @@ func (h *K8sHandler) RestartDeployment(c *gin.Context) {
|
||||
// ============================================================================
|
||||
|
||||
// ListHPAs 获取 HPA 列表
|
||||
func (h *K8sHandler) ListHPAs(c *gin.Context) {
|
||||
func (h *KubernetesHandler) ListHPAs(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
@@ -1083,7 +1083,7 @@ func (h *K8sHandler) ListHPAs(c *gin.Context) {
|
||||
}
|
||||
|
||||
// CreateHPA 创建 HPA
|
||||
func (h *K8sHandler) CreateHPA(c *gin.Context) {
|
||||
func (h *KubernetesHandler) CreateHPA(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
var req k8sclient.CreateHPARequest
|
||||
@@ -1112,7 +1112,7 @@ func (h *K8sHandler) CreateHPA(c *gin.Context) {
|
||||
}
|
||||
|
||||
// DeleteHPA 删除 HPA
|
||||
func (h *K8sHandler) DeleteHPA(c *gin.Context) {
|
||||
func (h *KubernetesHandler) DeleteHPA(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
name := c.Param("name")
|
||||
@@ -1136,7 +1136,7 @@ func (h *K8sHandler) DeleteHPA(c *gin.Context) {
|
||||
// ============================================================================
|
||||
|
||||
// ListCronJobs 获取 CronJob 列表
|
||||
func (h *K8sHandler) ListCronJobs(c *gin.Context) {
|
||||
func (h *KubernetesHandler) ListCronJobs(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
@@ -1155,7 +1155,7 @@ func (h *K8sHandler) ListCronJobs(c *gin.Context) {
|
||||
}
|
||||
|
||||
// CreateCronJob 创建 CronJob
|
||||
func (h *K8sHandler) CreateCronJob(c *gin.Context) {
|
||||
func (h *KubernetesHandler) CreateCronJob(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
|
||||
var req k8sclient.CreateCronJobRequest
|
||||
@@ -1180,7 +1180,7 @@ func (h *K8sHandler) CreateCronJob(c *gin.Context) {
|
||||
}
|
||||
|
||||
// SuspendCronJob 暂停/恢复 CronJob
|
||||
func (h *K8sHandler) SuspendCronJob(c *gin.Context) {
|
||||
func (h *KubernetesHandler) SuspendCronJob(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
name := c.Param("name")
|
||||
@@ -1209,7 +1209,7 @@ func (h *K8sHandler) SuspendCronJob(c *gin.Context) {
|
||||
}
|
||||
|
||||
// DeleteCronJob 删除 CronJob
|
||||
func (h *K8sHandler) DeleteCronJob(c *gin.Context) {
|
||||
func (h *KubernetesHandler) DeleteCronJob(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
name := c.Param("name")
|
||||
@@ -1229,7 +1229,7 @@ func (h *K8sHandler) DeleteCronJob(c *gin.Context) {
|
||||
}
|
||||
|
||||
// TriggerCronJob 手动触发 CronJob
|
||||
func (h *K8sHandler) TriggerCronJob(c *gin.Context) {
|
||||
func (h *KubernetesHandler) TriggerCronJob(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
name := c.Param("name")
|
||||
@@ -1253,7 +1253,7 @@ func (h *K8sHandler) TriggerCronJob(c *gin.Context) {
|
||||
// ============================================================================
|
||||
|
||||
// UpdateDeploymentImage 更新 Deployment 容器镜像 (CI webhook)
|
||||
func (h *K8sHandler) UpdateDeploymentImage(c *gin.Context) {
|
||||
func (h *KubernetesHandler) UpdateDeploymentImage(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
namespace := c.Param("namespace")
|
||||
name := c.Param("name")
|
||||
@@ -1290,8 +1290,12 @@ func (h *K8sHandler) UpdateDeploymentImage(c *gin.Context) {
|
||||
// ============================================================================
|
||||
|
||||
// ListNamespaces 获取命名空间列表
|
||||
func (h *K8sHandler) ListNamespaces(c *gin.Context) {
|
||||
func (h *KubernetesHandler) ListNamespaces(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
// Support clusterCode param from new routes
|
||||
if clusterID == 0 {
|
||||
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
|
||||
}
|
||||
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil {
|
||||
@@ -1308,6 +1312,355 @@ func (h *K8sHandler) ListNamespaces(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, models.Response{Code: 200, Data: namespaces})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ConfigMap & Secret (Kuboard-style namespace resources)
|
||||
// ============================================================================
|
||||
|
||||
// ListConfigMaps 获取命名空间下的 ConfigMap 列表
|
||||
func (h *KubernetesHandler) ListConfigMaps(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 {
|
||||
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
|
||||
}
|
||||
namespace := c.Param("namespace")
|
||||
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
cms, err := client.ListConfigMaps(namespace)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "K8s API error: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, models.Response{Code: 200, Data: cms.Items})
|
||||
}
|
||||
|
||||
// ListSecrets 获取命名空间下的 Secret 列表(仅名称+类型,不含值)
|
||||
func (h *KubernetesHandler) ListSecrets(c *gin.Context) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 {
|
||||
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
|
||||
}
|
||||
namespace := c.Param("namespace")
|
||||
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
secrets, err := client.ListSecrets(namespace)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "K8s API error: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, models.Response{Code: 200, Data: secrets.Items})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helpers
|
||||
// ============================================================================
|
||||
|
||||
// resolveClusterCode resolves a cluster code to its numeric ID
|
||||
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)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
|
||||
}
|
||||
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) ListDeploymentsNS(c *gin.Context) {
|
||||
h.listDeploymentsWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) ListPodsNS(c *gin.Context) {
|
||||
h.listPodsWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) ListServicesNS(c *gin.Context) {
|
||||
h.listServicesWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) ListIngressesNS(c *gin.Context) {
|
||||
h.listIngressesWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) ListHPAsNS(c *gin.Context) {
|
||||
h.listHPAsWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) CreateHPANS(c *gin.Context) {
|
||||
h.createHPAWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) DeleteHPANS(c *gin.Context) {
|
||||
h.deleteHPAWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) ListCronJobsNS(c *gin.Context) {
|
||||
h.listCronJobsWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) CreateCronJobNS(c *gin.Context) {
|
||||
h.createCronJobWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) SuspendCronJobNS(c *gin.Context) {
|
||||
h.suspendCronJobWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) TriggerCronJobNS(c *gin.Context) {
|
||||
h.triggerCronJobWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) DeleteCronJobNS(c *gin.Context) {
|
||||
h.deleteCronJobWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) ScaleDeploymentNS(c *gin.Context) {
|
||||
h.scaleDeploymentWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) RestartDeploymentNS(c *gin.Context) {
|
||||
h.restartDeploymentWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) UpdateDeploymentImageNS(c *gin.Context) {
|
||||
h.updateDeploymentImageWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) GetPodLogsNS(c *gin.Context) {
|
||||
h.getPodLogsWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
func (h *KubernetesHandler) ExecInPodNS(c *gin.Context) {
|
||||
h.execInPodWithNS(c, c.Param("namespace"))
|
||||
}
|
||||
|
||||
// Internal helpers that resolve clusterCode and inject namespace
|
||||
func (h *KubernetesHandler) listDeploymentsWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
deps, err := client.ListDeployments()
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
|
||||
type DepSummary struct {
|
||||
Namespace, Name string; Replicas, AvailableReplicas, ReadyReplicas int; Image string
|
||||
}
|
||||
result := []DepSummary{}
|
||||
for _, d := range deps.Items {
|
||||
if d.Metadata.Namespace != ns { continue }
|
||||
image := ""; if len(d.Spec.Template.Spec.Containers) > 0 { image = d.Spec.Template.Spec.Containers[0].Image }
|
||||
result = append(result, DepSummary{d.Metadata.Namespace, d.Metadata.Name, d.Spec.Replicas, d.Status.AvailableReplicas, d.Status.ReadyReplicas, image})
|
||||
}
|
||||
c.JSON(200, models.Response{Code: 200, Data: result})
|
||||
}
|
||||
func (h *KubernetesHandler) listPodsWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
pods, err := client.ListPods()
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
|
||||
type PodSummary struct { Namespace, Name, Status, NodeName, IP string; RestartCount int; Image string }
|
||||
result := []PodSummary{}
|
||||
for _, p := range pods.Items {
|
||||
if p.Metadata.Namespace != ns { continue }
|
||||
image := ""; if len(p.Spec.Containers) > 0 { image = p.Spec.Containers[0].Image }
|
||||
restarts := 0; if len(p.Status.ContainerStatuses) > 0 { restarts = p.Status.ContainerStatuses[0].RestartCount }
|
||||
result = append(result, PodSummary{p.Metadata.Namespace, p.Metadata.Name, p.Status.Phase, p.Spec.NodeName, p.Status.PodIP, restarts, image})
|
||||
}
|
||||
c.JSON(200, models.Response{Code: 200, Data: result})
|
||||
}
|
||||
func (h *KubernetesHandler) listServicesWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
svcs, err := client.ListServices()
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
|
||||
type SvcSummary struct { Namespace, Name, Type, ClusterIP string; Ports int }
|
||||
result := []SvcSummary{}
|
||||
for _, s := range svcs.Items {
|
||||
if s.Metadata.Namespace != ns { continue }
|
||||
result = append(result, SvcSummary{s.Metadata.Namespace, s.Metadata.Name, s.Spec.Type, s.Spec.ClusterIP, len(s.Spec.Ports)})
|
||||
}
|
||||
c.JSON(200, models.Response{Code: 200, Data: result})
|
||||
}
|
||||
func (h *KubernetesHandler) listIngressesWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
ings, err := client.ListIngresses()
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
|
||||
type IngSummary struct { Namespace, Name string; Hosts []string; TLS bool }
|
||||
result := []IngSummary{}
|
||||
for _, ing := range ings.Items {
|
||||
if ing.Metadata.Namespace != ns { continue }
|
||||
hosts := []string{}
|
||||
for _, rule := range ing.Spec.Rules { if rule.Host != "" { hosts = append(hosts, rule.Host) } }
|
||||
result = append(result, IngSummary{ing.Metadata.Namespace, ing.Metadata.Name, hosts, len(ing.Spec.TLS) > 0})
|
||||
}
|
||||
c.JSON(200, models.Response{Code: 200, Data: result})
|
||||
}
|
||||
func (h *KubernetesHandler) listHPAsWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
hpas, err := client.ListHPAs()
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
|
||||
filtered := []k8sclient.HPAItem{}
|
||||
for _, h := range hpas.Items { if h.Metadata.Namespace == ns { filtered = append(filtered, h) } }
|
||||
c.JSON(200, models.Response{Code: 200, Data: filtered})
|
||||
}
|
||||
func (h *KubernetesHandler) createHPAWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
var req k8sclient.CreateHPARequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, models.Response{Code: 400, Message: "参数错误"}); return }
|
||||
if req.Namespace == "" { req.Namespace = ns }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
hpa, err := client.CreateHPA(req)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "创建失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Data: hpa})
|
||||
}
|
||||
func (h *KubernetesHandler) deleteHPAWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
if err := client.DeleteHPA(ns, c.Param("name")); err != nil { c.JSON(500, models.Response{Code: 500, Message: "删除失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Message: "已删除"})
|
||||
}
|
||||
func (h *KubernetesHandler) listCronJobsWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
cjs, err := client.ListCronJobs()
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
|
||||
filtered := []k8sclient.CronJobItem{}
|
||||
for _, cj := range cjs.Items { if cj.Metadata.Namespace == ns { filtered = append(filtered, cj) } }
|
||||
c.JSON(200, models.Response{Code: 200, Data: filtered})
|
||||
}
|
||||
func (h *KubernetesHandler) createCronJobWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
var req k8sclient.CreateCronJobRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, models.Response{Code: 400, Message: "参数错误"}); return }
|
||||
if req.Namespace == "" { req.Namespace = ns }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
cj, err := client.CreateCronJob(req)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "创建失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Data: cj})
|
||||
}
|
||||
func (h *KubernetesHandler) suspendCronJobWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
var req struct { Suspend bool `json:"suspend"` }; c.ShouldBindJSON(&req)
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
if err := client.SuspendCronJob(ns, c.Param("name"), req.Suspend); err != nil { c.JSON(500, models.Response{Code: 500, Message: "操作失败: " + err.Error()}); return }
|
||||
action := "恢复"; if req.Suspend { action = "暂停" }
|
||||
c.JSON(200, models.Response{Code: 200, Message: "CronJob 已" + action})
|
||||
}
|
||||
func (h *KubernetesHandler) triggerCronJobWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
if err := client.TriggerCronJob(ns, c.Param("name")); err != nil { c.JSON(500, models.Response{Code: 500, Message: "触发失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Message: "手动触发成功"})
|
||||
}
|
||||
func (h *KubernetesHandler) deleteCronJobWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
if err := client.DeleteCronJob(ns, c.Param("name")); err != nil { c.JSON(500, models.Response{Code: 500, Message: "删除失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Message: "已删除"})
|
||||
}
|
||||
func (h *KubernetesHandler) scaleDeploymentWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
var req struct { Replicas int `json:"replicas"` }
|
||||
if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, models.Response{Code: 400, Message: "参数错误"}); return }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
if err := client.ScaleDeployment(ns, c.Param("name"), req.Replicas); err != nil { c.JSON(500, models.Response{Code: 500, Message: "扩缩容失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Message: fmt.Sprintf("已设置为 %d 副本", req.Replicas)})
|
||||
}
|
||||
func (h *KubernetesHandler) restartDeploymentWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
if err := client.RestartDeployment(ns, c.Param("name")); err != nil { c.JSON(500, models.Response{Code: 500, Message: "重启失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Message: "重启指令已下发"})
|
||||
}
|
||||
func (h *KubernetesHandler) updateDeploymentImageWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
var req struct { Image string `json:"image"`; ContainerName string `json:"container_name"` }
|
||||
if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, models.Response{Code: 400, Message: "参数错误"}); return }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
if err := client.UpdateDeploymentImage(ns, c.Param("name"), req.ContainerName, req.Image); err != nil { c.JSON(500, models.Response{Code: 500, Message: "更新镜像失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Message: fmt.Sprintf("镜像已更新为 %s", req.Image)})
|
||||
}
|
||||
func (h *KubernetesHandler) getPodLogsWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
podName := c.Param("podName")
|
||||
container := c.Query("container")
|
||||
tailLines, _ := strconv.Atoi(c.DefaultQuery("tail", "200"))
|
||||
stream := c.Query("stream") == "true"
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
if stream {
|
||||
body, err := client.GetPodLogsStream(ns, podName, container, tailLines)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "获取日志流失败: " + err.Error()}); return }
|
||||
defer body.Close()
|
||||
c.Header("Content-Type", "text/plain; charset=utf-8")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
buf := make([]byte, 4096); n, err := body.Read(buf)
|
||||
if n > 0 { w.Write(buf[:n]); return true }
|
||||
return err == nil
|
||||
})
|
||||
return
|
||||
}
|
||||
logs, err := client.GetPodLogs(ns, podName, container, tailLines)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "获取日志失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Data: gin.H{"logs": logs, "pod": podName, "namespace": ns}})
|
||||
}
|
||||
func (h *KubernetesHandler) execInPodWithNS(c *gin.Context, ns string) {
|
||||
clusterID, _ := strconv.Atoi(c.Param("id"))
|
||||
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
|
||||
podName := c.Param("podName")
|
||||
var req struct { Command []string `json:"command"`; Container string `json:"container"` }
|
||||
if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, models.Response{Code: 400, Message: "参数错误"}); return }
|
||||
client, _, err := h.getK8sClient(clusterID)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: err.Error()}); return }
|
||||
result, err := client.ExecInPod(ns, podName, req.Container, req.Command)
|
||||
if err != nil { c.JSON(500, models.Response{Code: 500, Message: "执行失败: " + err.Error()}); return }
|
||||
c.JSON(200, models.Response{Code: 200, Data: result})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helpers
|
||||
// ============================================================================
|
||||
@@ -1342,8 +1695,8 @@ func parseMemResource(val string) int64 {
|
||||
|
||||
|
||||
// getK8sClient builds a K8s API client from cluster's stored kubeconfig
|
||||
func (h *K8sHandler) getK8sClient(clusterID int) (*k8sclient.Client, *models.K8sCluster, error) {
|
||||
var cluster models.K8sCluster
|
||||
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")
|
||||
}
|
||||
@@ -65,8 +65,8 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
|
||||
r.GET("/ws/metrics", middleware.JWTAuth(&cfg.JWT), metricsWSHandler.ServeWS)
|
||||
|
||||
// WebSocket K8s exec 交互终端 // Logan.Li
|
||||
k8sHandler := handlers.NewK8sHandler(db)
|
||||
r.GET("/ws/k8s-exec/:id/namespaces/:namespace/pods/:podName", middleware.JWTAuth(&cfg.JWT), k8sHandler.ExecTerminal)
|
||||
k8sHandler := handlers.NewKubernetesHandler(db)
|
||||
r.GET("/ws/kubernetes-exec/:id/namespaces/:namespace/pods/:podName", middleware.JWTAuth(&cfg.JWT), k8sHandler.ExecTerminal)
|
||||
|
||||
// 公开路由
|
||||
authHandler := handlers.NewUserHandler(db, cfg)
|
||||
@@ -235,7 +235,7 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
|
||||
}
|
||||
|
||||
// K8s集群路由
|
||||
clusters := authorized.Group("/k8s-clusters")
|
||||
clusters := authorized.Group("/kubernetes-clusters")
|
||||
{
|
||||
clusters.GET("", k8sHandler.ListClusters)
|
||||
clusters.GET("/:id", k8sHandler.GetCluster)
|
||||
@@ -275,6 +275,53 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
|
||||
clusters.GET("/:id/namespaces", k8sHandler.ListNamespaces)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Kuboard-style namespace-scoped routes (/kubernetes/{clusterCode}/namespace/{ns}/...)
|
||||
// ============================================================================
|
||||
kubernetesRouter := authorized.Group("/kubernetes")
|
||||
{
|
||||
// Namespace overview
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace", func(c *gin.Context) {
|
||||
k8sHandler.ListDeploymentsNS(c)
|
||||
})
|
||||
|
||||
// Deployments
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/deployments", k8sHandler.ListDeploymentsNS)
|
||||
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/deployments/:name/scale", k8sHandler.ScaleDeploymentNS)
|
||||
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/deployments/:name/restart", k8sHandler.RestartDeploymentNS)
|
||||
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/deployments/:name/update-image", k8sHandler.UpdateDeploymentImageNS)
|
||||
|
||||
// Pods
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/pods", k8sHandler.ListPodsNS)
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/pods/:podName/logs", k8sHandler.GetPodLogsNS)
|
||||
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/pods/:podName/exec", k8sHandler.ExecInPodNS)
|
||||
|
||||
// Services
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/services", k8sHandler.ListServicesNS)
|
||||
|
||||
// Ingresses
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/ingresses", k8sHandler.ListIngressesNS)
|
||||
|
||||
// HPA
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/hpas", k8sHandler.ListHPAsNS)
|
||||
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/hpas", k8sHandler.CreateHPANS)
|
||||
kubernetesRouter.DELETE("/:clusterCode/namespace/:namespace/hpas/:name", k8sHandler.DeleteHPANS)
|
||||
|
||||
// CronJob
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/cronjobs", k8sHandler.ListCronJobsNS)
|
||||
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/cronjobs", k8sHandler.CreateCronJobNS)
|
||||
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/cronjobs/:name/suspend", k8sHandler.SuspendCronJobNS)
|
||||
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/cronjobs/:name/trigger", k8sHandler.TriggerCronJobNS)
|
||||
kubernetesRouter.DELETE("/:clusterCode/namespace/:namespace/cronjobs/:name", k8sHandler.DeleteCronJobNS)
|
||||
|
||||
// ConfigMap / Secret
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/configmaps", k8sHandler.ListConfigMaps)
|
||||
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/secrets", k8sHandler.ListSecrets)
|
||||
|
||||
// Namespace list
|
||||
kubernetesRouter.GET("/:clusterCode/namespaces", k8sHandler.ListNamespaces)
|
||||
}
|
||||
|
||||
// 告警路由
|
||||
alertHandler := handlers.NewAlertHandler(db)
|
||||
alerts := authorized.Group("/alerts")
|
||||
|
||||
Reference in new issue
Block a user