Skip to main content
Glama
metadata.go6.57 kB
package dynamic import ( "fmt" "github.com/duke-git/lancet/v2/slice" "github.com/gin-gonic/gin" "github.com/weibaohui/k8m/pkg/comm/utils/amis" "github.com/weibaohui/kom/kom" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) type MetadataController struct{} func RegisterMetadataRoutes(api *gin.RouterGroup) { ctrl := &MetadataController{} api.POST("/:kind/group/:group/version/:version/update_labels/ns/:ns/name/:name", ctrl.UpdateLabels) // CRD api.GET("/:kind/group/:group/version/:version/annotations/ns/:ns/name/:name", ctrl.ListAnnotations) // CRD api.POST("/:kind/group/:group/version/:version/update_annotations/ns/:ns/name/:name", ctrl.UpdateAnnotations) // CRD } // @Summary 更新资源标签 // @Security BearerAuth // @Param cluster query string true "集群名称" // @Param kind path string true "资源类型" // @Param group path string true "资源组" // @Param version path string true "资源版本" // @Param ns path string true "命名空间" // @Param name path string true "资源名称" // @Param labels body map[string]string true "标签键值对" // @Success 200 {object} string // @Router /k8s/cluster/{cluster}/{kind}/group/{group}/version/{version}/update_labels/ns/{ns}/name/{name} [post] func (mc *MetadataController) UpdateLabels(c *gin.Context) { ns := c.Param("ns") name := c.Param("name") kind := c.Param("kind") group := c.Param("group") version := c.Param("version") ctx := amis.GetContextWithUser(c) selectedCluster, err := amis.GetSelectedCluster(c) if err != nil { amis.WriteJsonError(c, err) return } var req struct { Labels map[string]string `json:"labels"` } if err = c.ShouldBindJSON(&req); err != nil { amis.WriteJsonError(c, err) return } var obj *unstructured.Unstructured err = kom.Cluster(selectedCluster).WithContext(ctx). Name(name).Namespace(ns). CRD(group, version, kind). Get(&obj).Error if err != nil { amis.WriteJsonError(c, err) return } obj.SetLabels(req.Labels) err = kom.Cluster(selectedCluster).WithContext(ctx). Name(name).Namespace(ns). CRD(group, version, kind). Update(obj).Error if err != nil { amis.WriteJsonError(c, err) return } amis.WriteJsonOK(c) } // 部分key为k8m增加的指标数据,不是资源自身的注解,因此过滤掉。 // last-applied-configuration是k8s管理的,不允许修改。 // 注意同步修改前端的assets/public/custom.js里面的filterAnnotations方法 var immutableKeys = []string{ "cpu.request", "cpu.requestFraction", "cpu.limit", "cpu.limitFraction", "cpu.total", "cpu.realtime", "memory.request", "memory.requestFraction", "memory.limit", "memory.limitFraction", "memory.total", "memory.realtime", "ip.usage.total", "ip.usage.used", "ip.usage.available", "pod.count.total", "pod.count.used", "pod.count.available", "kubectl.kubernetes.io/last-applied-configuration", "kom.kubernetes.io/restartedAt", "pvc.count", "pv.count", "ingress.count", } // @Summary 列出资源注解 // @Security BearerAuth // @Param cluster query string true "集群名称" // @Param kind path string true "资源类型" // @Param group path string true "资源组" // @Param version path string true "资源版本" // @Param ns path string true "命名空间" // @Param name path string true "资源名称" // @Success 200 {object} map[string]string // @Router /k8s/cluster/{cluster}/{kind}/group/{group}/version/{version}/annotations/ns/{ns}/name/{name} [get] func (mc *MetadataController) ListAnnotations(c *gin.Context) { ns := c.Param("ns") name := c.Param("name") kind := c.Param("kind") group := c.Param("group") version := c.Param("version") ctx := amis.GetContextWithUser(c) selectedCluster, err := amis.GetSelectedCluster(c) if err != nil { amis.WriteJsonError(c, err) return } var obj *unstructured.Unstructured err = kom.Cluster(selectedCluster).WithContext(ctx). Name(name).Namespace(ns). CRD(group, version, kind). Get(&obj).Error if err != nil { amis.WriteJsonError(c, err) return } annotations := obj.GetAnnotations() // 排除immutableKeys for _, key := range immutableKeys { delete(annotations, key) } amis.WriteJsonData(c, gin.H{ "annotations": annotations, }) } // @Summary 更新资源注解 // @Security BearerAuth // @Param cluster query string true "集群名称" // @Param kind path string true "资源类型" // @Param group path string true "资源组" // @Param version path string true "资源版本" // @Param ns path string true "命名空间" // @Param name path string true "资源名称" // @Param annotations body map[string]any true "注解键值对" // @Success 200 {object} string // @Router /k8s/cluster/{cluster}/{kind}/group/{group}/version/{version}/update_annotations/ns/{ns}/name/{name} [post] func (mc *MetadataController) UpdateAnnotations(c *gin.Context) { ns := c.Param("ns") name := c.Param("name") kind := c.Param("kind") group := c.Param("group") version := c.Param("version") ctx := amis.GetContextWithUser(c) selectedCluster, err := amis.GetSelectedCluster(c) if err != nil { amis.WriteJsonError(c, err) return } var req struct { Annotations map[string]any `json:"annotations"` } if err := c.ShouldBindJSON(&req); err != nil { amis.WriteJsonError(c, err) return } // 判断下前台传来的annotations是否是immutableKeys中的key,如果是则不允许修改 // 创建一个新的map,用于存储过滤后的annotations filteredAnnotations := make(map[string]string) for k, v := range req.Annotations { if !slice.Contain(immutableKeys, k) { filteredAnnotations[k] = fmt.Sprintf("%s", v) } } // 判断是否还有值,有值再更新 if len(filteredAnnotations) == 0 { amis.WriteJsonOK(c) return } var obj *unstructured.Unstructured err = kom.Cluster(selectedCluster).WithContext(ctx). Name(name).Namespace(ns). CRD(group, version, kind). Get(&obj).Error if err != nil { amis.WriteJsonError(c, err) return } // 单独处理kubectl.kubernetes.io/last-applied-configuration // 这个要用原来的覆盖 if obj.GetAnnotations()["kubectl.kubernetes.io/last-applied-configuration"] != "" { filteredAnnotations["kubectl.kubernetes.io/last-applied-configuration"] = obj.GetAnnotations()["kubectl.kubernetes.io/last-applied-configuration"] } obj.SetAnnotations(filteredAnnotations) err = kom.Cluster(selectedCluster).WithContext(ctx). Name(name).Namespace(ns). CRD(group, version, kind). Update(obj).Error if err != nil { amis.WriteJsonError(c, err) return } amis.WriteJsonOK(c) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/weibaohui/k8m'

If you have feedback or need assistance with the MCP directory API, please join our Discord server