This commit is contained in:
Logan committed 2026-07-09 14:16:56 +08:00
1 parent 0690285147
commit 5618cd2738
154 files changed
+5021 -3161

No files matched your search

+357 -98
View File
@@ -208,15 +208,25 @@ func (h *KubernetesHandler) GetDeploymentNS(c *gin.Context) {
ns := c.Param("namespace")
name := c.Param("name")
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
deps, err := client.ListDeployments()
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
for _, d := range deps.Items {
if d.Metadata.Namespace == ns && d.Metadata.Name == name {
image := ""
if len(d.Spec.Template.Spec.Containers) > 0 { image = d.Spec.Template.Spec.Containers[0].Image }
if len(d.Spec.Template.Spec.Containers) > 0 {
image = d.Spec.Template.Spec.Containers[0].Image
}
c.JSON(200, model.Response{Code: 200, Data: map[string]interface{}{
"namespace": d.Metadata.Namespace,
"name": d.Metadata.Name,
@@ -248,11 +258,19 @@ func (h *KubernetesHandler) ResumeDeploymentNS(c *gin.Context) {
}
func (h *KubernetesHandler) listDeploymentsWithNS(c *gin.Context, ns string) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
deps, err := client.ListDeployments()
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
type DepSummary struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
@@ -265,8 +283,13 @@ func (h *KubernetesHandler) listDeploymentsWithNS(c *gin.Context, ns 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 }
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{
Namespace: d.Metadata.Namespace,
Name: d.Metadata.Name,
@@ -275,63 +298,131 @@ func (h *KubernetesHandler) listDeploymentsWithNS(c *gin.Context, ns string) {
ReadyReplicas: d.Status.ReadyReplicas,
Image: image,
Paused: d.Spec.Paused,
Selector: func() map[string]string { if d.Spec.Selector != nil { return d.Spec.Selector.MatchLabels }; return nil }(),
Selector: func() map[string]string {
if d.Spec.Selector != nil {
return d.Spec.Selector.MatchLabels
}
return nil
}(),
})
}
c.JSON(200, model.Response{Code: 200, Data: result})
}
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, model.Response{Code: 400, Message: "参数错误"}); return }
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, model.Response{Code: 400, Message: "参数错误"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err := client.ScaleDeployment(ns, c.Param("name"), req.Replicas); err != nil { c.JSON(500, model.Response{Code: 500, Message: "扩缩容失败: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
if err := client.ScaleDeployment(ns, c.Param("name"), req.Replicas); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "扩缩容失败: " + err.Error()})
return
}
c.JSON(200, model.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")) }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err := client.RestartDeployment(ns, c.Param("name")); err != nil { c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
if err := client.RestartDeployment(ns, c.Param("name")); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()})
return
}
c.JSON(200, model.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, model.Response{Code: 400, Message: "参数错误"}); return }
if strings.TrimSpace(req.Image) == "" { c.JSON(400, model.Response{Code: 400, Message: "image 不能为空"}); return }
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, model.Response{Code: 400, Message: "参数错误"})
return
}
if strings.TrimSpace(req.Image) == "" {
c.JSON(400, model.Response{Code: 400, Message: "image 不能为空"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err := client.UpdateDeploymentImage(ns, c.Param("name"), req.ContainerName, req.Image); err != nil { c.JSON(500, model.Response{Code: 500, Message: "更新镜像失败: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
if err := client.UpdateDeploymentImage(ns, c.Param("name"), req.ContainerName, req.Image); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "更新镜像失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: fmt.Sprintf("镜像已更新为 %s", req.Image)})
}
func (h *KubernetesHandler) pauseDeploymentWithNS(c *gin.Context, ns string) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err := client.PauseDeployment(ns, c.Param("name")); err != nil { c.JSON(500, model.Response{Code: 500, Message: "暂停更新失败: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
if err := client.PauseDeployment(ns, c.Param("name")); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "暂停更新失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: "已暂停滚动更新"})
}
func (h *KubernetesHandler) resumeDeploymentWithNS(c *gin.Context, ns string) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err := client.ResumeDeployment(ns, c.Param("name")); err != nil { c.JSON(500, model.Response{Code: 500, Message: "恢复更新失败: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
if err := client.ResumeDeployment(ns, c.Param("name")); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "恢复更新失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: "已恢复滚动更新"})
}
func (h *KubernetesHandler) ListDeploymentsAllNS(c *gin.Context) {
clusterID := h.resolveClusterCode(c.Param("clusterCode"))
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
deps, err := client.ListDeployments()
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
type DepSummary struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
@@ -342,7 +433,10 @@ func (h *KubernetesHandler) ListDeploymentsAllNS(c *gin.Context) {
}
result := []DepSummary{}
for _, d := range deps.Items {
image := ""; if len(d.Spec.Template.Spec.Containers) > 0 { image = d.Spec.Template.Spec.Containers[0].Image }
image := ""
if len(d.Spec.Template.Spec.Containers) > 0 {
image = d.Spec.Template.Spec.Containers[0].Image
}
result = append(result, DepSummary{
Namespace: d.Metadata.Namespace,
Name: d.Metadata.Name,
@@ -358,11 +452,20 @@ func (h *KubernetesHandler) ListDeploymentsAllNS(c *gin.Context) {
// ListPodsAllNS lists all pods across all namespaces using clusterCode.
func (h *KubernetesHandler) ListStatefulSetsNS(c *gin.Context) {
clusterID := h.resolveClusterCode(c.Param("clusterCode"))
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
sts, err := client.ListStatefulSets()
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
ns := c.Param("namespace")
type StsSummary struct {
Namespace string `json:"namespace"`
@@ -373,8 +476,13 @@ func (h *KubernetesHandler) ListStatefulSetsNS(c *gin.Context) {
}
result := []StsSummary{}
for _, s := range sts.Items {
if s.Metadata.Namespace != ns { continue }
image := ""; if len(s.Spec.Template.Spec.Containers) > 0 { image = s.Spec.Template.Spec.Containers[0].Image }
if s.Metadata.Namespace != ns {
continue
}
image := ""
if len(s.Spec.Template.Spec.Containers) > 0 {
image = s.Spec.Template.Spec.Containers[0].Image
}
result = append(result, StsSummary{
Namespace: s.Metadata.Namespace,
Name: s.Metadata.Name,
@@ -389,11 +497,20 @@ func (h *KubernetesHandler) ListStatefulSetsNS(c *gin.Context) {
// ListDaemonSetsNS lists DaemonSets in a namespace
func (h *KubernetesHandler) ListDaemonSetsNS(c *gin.Context) {
clusterID := h.resolveClusterCode(c.Param("clusterCode"))
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ds, err := client.ListDaemonSets()
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
ns := c.Param("namespace")
type DsSummary struct {
Namespace string `json:"namespace"`
@@ -405,8 +522,13 @@ func (h *KubernetesHandler) ListDaemonSetsNS(c *gin.Context) {
}
result := []DsSummary{}
for _, d := range ds.Items {
if d.Metadata.Namespace != ns { continue }
image := ""; if len(d.Spec.Template.Spec.Containers) > 0 { image = d.Spec.Template.Spec.Containers[0].Image }
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, DsSummary{
Namespace: d.Metadata.Namespace,
Name: d.Metadata.Name,
@@ -418,18 +540,31 @@ func (h *KubernetesHandler) ListDaemonSetsNS(c *gin.Context) {
}
c.JSON(200, model.Response{Code: 200, Data: result})
}
// ScaleStatefulSetNS scales a StatefulSet (Kuboard code route)
func (h *KubernetesHandler) ScaleStatefulSetNS(c *gin.Context) {
clusterID := h.resolveClusterCode(c.Param("clusterCode"))
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ns := c.Param("namespace")
name := c.Param("name")
var req struct{ Replicas int `json:"replicas"` }
if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, model.Response{Code: 400, Message: "参数错误"}); return }
var req struct {
Replicas int `json:"replicas"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, model.Response{Code: 400, Message: "参数错误"})
return
}
if err := client.ScaleStatefulSet(ns, name, req.Replicas); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "扩缩容失败: " + err.Error()}); return
c.JSON(500, model.Response{Code: 500, Message: "扩缩容失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: "StatefulSet 副本数已更新为 " + strconv.Itoa(req.Replicas)})
}
@@ -437,16 +572,30 @@ func (h *KubernetesHandler) ScaleStatefulSetNS(c *gin.Context) {
// ScaleStatefulSet scales a StatefulSet (ID route)
func (h *KubernetesHandler) ScaleStatefulSet(c *gin.Context) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ns := c.Param("namespace")
name := c.Param("name")
var req struct{ Replicas int `json:"replicas"` }
if err := c.ShouldBindJSON(&req); err != nil { c.JSON(400, model.Response{Code: 400, Message: "参数错误"}); return }
var req struct {
Replicas int `json:"replicas"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, model.Response{Code: 400, Message: "参数错误"})
return
}
if err := client.ScaleStatefulSet(ns, name, req.Replicas); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "扩缩容失败: " + err.Error()}); return
c.JSON(500, model.Response{Code: 500, Message: "扩缩容失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: "StatefulSet 副本数已更新为 " + strconv.Itoa(req.Replicas)})
}
@@ -454,13 +603,20 @@ func (h *KubernetesHandler) ScaleStatefulSet(c *gin.Context) {
// RestartStatefulSetNS restarts a StatefulSet (Kuboard code route)
func (h *KubernetesHandler) RestartStatefulSetNS(c *gin.Context) {
clusterID := h.resolveClusterCode(c.Param("clusterCode"))
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ns := c.Param("namespace")
name := c.Param("name")
if err := client.RestartStatefulSet(ns, name); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()}); return
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: "StatefulSet 滚动重启已触发"})
}
@@ -468,14 +624,23 @@ func (h *KubernetesHandler) RestartStatefulSetNS(c *gin.Context) {
// RestartStatefulSet restarts a StatefulSet (ID route)
func (h *KubernetesHandler) RestartStatefulSet(c *gin.Context) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ns := c.Param("namespace")
name := c.Param("name")
if err := client.RestartStatefulSet(ns, name); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()}); return
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: "StatefulSet 滚动重启已触发"})
}
@@ -483,13 +648,20 @@ func (h *KubernetesHandler) RestartStatefulSet(c *gin.Context) {
// RestartDaemonSetNS restarts a DaemonSet (Kuboard code route)
func (h *KubernetesHandler) RestartDaemonSetNS(c *gin.Context) {
clusterID := h.resolveClusterCode(c.Param("clusterCode"))
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ns := c.Param("namespace")
name := c.Param("name")
if err := client.RestartDaemonSet(ns, name); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()}); return
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: "DaemonSet 滚动重启已触发"})
}
@@ -497,14 +669,23 @@ func (h *KubernetesHandler) RestartDaemonSetNS(c *gin.Context) {
// RestartDaemonSet restarts a DaemonSet (ID route)
func (h *KubernetesHandler) RestartDaemonSet(c *gin.Context) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ns := c.Param("namespace")
name := c.Param("name")
if err := client.RestartDaemonSet(ns, name); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()}); return
c.JSON(500, model.Response{Code: 500, Message: "重启失败: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Message: "DaemonSet 滚动重启已触发"})
}
@@ -512,26 +693,44 @@ func (h *KubernetesHandler) RestartDaemonSet(c *gin.Context) {
// GetStatefulSetDetailNS returns a single StatefulSet detail (Kuboard code route)
func (h *KubernetesHandler) GetStatefulSetDetailNS(c *gin.Context) {
clusterID := h.resolveClusterCode(c.Param("clusterCode"))
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ns := c.Param("namespace")
name := c.Param("name")
sts, err := client.GetStatefulSet(ns, name)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Data: sts})
}
// GetDaemonSetDetailNS returns a single DaemonSet detail (Kuboard code route)
func (h *KubernetesHandler) GetDaemonSetDetailNS(c *gin.Context) {
clusterID := h.resolveClusterCode(c.Param("clusterCode"))
if clusterID == 0 { c.JSON(500, model.Response{Code: 500, Message: "cluster not found"}); return }
if clusterID == 0 {
c.JSON(500, model.Response{Code: 500, Message: "cluster not found"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
ns := c.Param("namespace")
name := c.Param("name")
ds, err := client.GetDaemonSet(ns, name)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
c.JSON(200, model.Response{Code: 200, Data: ds})
}
@@ -545,11 +744,19 @@ func (h *KubernetesHandler) ListReplicaSetsNS(c *gin.Context) {
}
func (h *KubernetesHandler) listReplicaSetsWithNS(c *gin.Context, ns string) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
items, err := client.ListReplicaSetsRaw(ns)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
type RSSummary struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
@@ -564,11 +771,16 @@ func (h *KubernetesHandler) listReplicaSetsWithNS(c *gin.Context, ns string) {
result := []RSSummary{}
for _, rs := range items {
image := ""
if len(rs.Spec.Template.Spec.Containers) > 0 { image = rs.Spec.Template.Spec.Containers[0].Image }
if len(rs.Spec.Template.Spec.Containers) > 0 {
image = rs.Spec.Template.Spec.Containers[0].Image
}
revision := rs.Metadata.Annotations["deployment.kubernetes.io/revision"]
owner := ""
for _, o := range rs.Metadata.OwnerReferences {
if o.Kind == "Deployment" { owner = o.Name; break }
if o.Kind == "Deployment" {
owner = o.Name
break
}
}
result = append(result, RSSummary{
Namespace: rs.Metadata.Namespace,
@@ -591,13 +803,24 @@ func (h *KubernetesHandler) ListDeploymentRevisionsNS(c *gin.Context) {
}
func (h *KubernetesHandler) listDeploymentRevisionsWithNS(c *gin.Context, ns string) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
deploymentName := c.Param("name")
if deploymentName == "" { c.JSON(400, model.Response{Code: 400, Message: "缺少 deployment name"}); return }
if deploymentName == "" {
c.JSON(400, model.Response{Code: 400, Message: "缺少 deployment name"})
return
}
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
items, err := client.ListReplicaSetsRaw(ns)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "K8s API error: " + err.Error()})
return
}
type Revision struct {
Revision string `json:"revision"`
ReplicaSet string `json:"replica_set"`
@@ -610,11 +833,18 @@ func (h *KubernetesHandler) listDeploymentRevisionsWithNS(c *gin.Context, ns str
for _, rs := range items {
isOwner := false
for _, o := range rs.Metadata.OwnerReferences {
if o.Kind == "Deployment" && o.Name == deploymentName { isOwner = true; break }
if o.Kind == "Deployment" && o.Name == deploymentName {
isOwner = true
break
}
}
if !isOwner {
continue
}
if !isOwner { continue }
image := ""
if len(rs.Spec.Template.Spec.Containers) > 0 { image = rs.Spec.Template.Spec.Containers[0].Image }
if len(rs.Spec.Template.Spec.Containers) > 0 {
image = rs.Spec.Template.Spec.Containers[0].Image
}
result = append(result, Revision{
Revision: rs.Metadata.Annotations["deployment.kubernetes.io/revision"],
ReplicaSet: rs.Metadata.Name,
@@ -639,28 +869,44 @@ func (h *KubernetesHandler) RollbackDeploymentNS(c *gin.Context) {
}
func (h *KubernetesHandler) rollbackDeploymentWithNS(c *gin.Context, ns string) {
clusterID, _ := strconv.Atoi(c.Param("id"))
if clusterID == 0 { clusterID = h.resolveClusterCode(c.Param("clusterCode")) }
if clusterID == 0 {
clusterID = h.resolveClusterCode(c.Param("clusterCode"))
}
deploymentName := c.Param("name")
if deploymentName == "" { c.JSON(400, model.Response{Code: 400, Message: "缺少 deployment name"}); return }
if deploymentName == "" {
c.JSON(400, model.Response{Code: 400, Message: "缺少 deployment name"})
return
}
var req struct {
Revision int `json:"revision"`
ReplicaSet string `json:"replicaSet"`
}
_ = c.ShouldBindJSON(&req) // 允许空 body(但下面会校验)
client, _, err := h.getK8sClient(clusterID)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: err.Error()})
return
}
targetRS := req.ReplicaSet
// 通过 revision 定位 ReplicaSet
if targetRS == "" && req.Revision > 0 {
items, err := client.ListReplicaSetsRaw(ns)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "获取 ReplicaSet 列表失败: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "获取 ReplicaSet 列表失败: " + err.Error()})
return
}
for _, rs := range items {
isOwner := false
for _, o := range rs.Metadata.OwnerReferences {
if o.Kind == "Deployment" && o.Name == deploymentName { isOwner = true; break }
if o.Kind == "Deployment" && o.Name == deploymentName {
isOwner = true
break
}
}
if !isOwner {
continue
}
if !isOwner { continue }
if rs.Metadata.Annotations["deployment.kubernetes.io/revision"] == strconv.Itoa(req.Revision) {
targetRS = rs.Metadata.Name
break
@@ -671,18 +917,31 @@ func (h *KubernetesHandler) rollbackDeploymentWithNS(c *gin.Context, ns string)
return
}
}
if targetRS == "" { c.JSON(400, model.Response{Code: 400, Message: "需要 revision 或 replicaSet 参数"}); return }
if targetRS == "" {
c.JSON(400, model.Response{Code: 400, Message: "需要 revision 或 replicaSet 参数"})
return
}
// 取 ReplicaSet 的 template,patch 到 Deployment.spec.template 实现回滚
rsJSON, err := client.GetReplicaSet(ns, targetRS)
if err != nil { c.JSON(500, model.Response{Code: 500, Message: "获取 ReplicaSet 失败: " + err.Error()}); return }
if err != nil {
c.JSON(500, model.Response{Code: 500, Message: "获取 ReplicaSet 失败: " + err.Error()})
return
}
specMap, ok := rsJSON["spec"].(map[string]interface{})
if !ok { c.JSON(500, model.Response{Code: 500, Message: "ReplicaSet 缺少 spec"}); return }
if !ok {
c.JSON(500, model.Response{Code: 500, Message: "ReplicaSet 缺少 spec"})
return
}
template, ok := specMap["template"].(map[string]interface{})
if !ok { c.JSON(500, model.Response{Code: 500, Message: "ReplicaSet 缺少 template"}); return }
if !ok {
c.JSON(500, model.Response{Code: 500, Message: "ReplicaSet 缺少 template"})
return
}
if err := client.PatchDeploymentSpecTemplate(ns, deploymentName, template); err != nil {
c.JSON(500, model.Response{Code: 500, Message: "回滚失败: " + err.Error()}); return
c.JSON(500, model.Response{Code: 500, Message: "回滚失败: " + err.Error()})
return
}
c.JSON(200, model.Response{
Code: 200,