From b266170278ca8db3d55b054960312f3bf55cb5ff Mon Sep 17 00:00:00 2001 From: weibaohui Date: Tue, 22 Oct 2024 20:58:46 +0800 Subject: [PATCH] =?UTF-8?q?refactor(kubectl):=20=E9=87=8D=E6=9E=84=20kubec?= =?UTF-8?q?tl=20=E6=A8=A1=E5=9D=97=E5=B9=B6=E7=A7=BB=E9=99=A4=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除了 kubectl 模块中的大量未使用代码 - 移除了 apply.go、client.go、dynamic.go 等多个文件 - 保留了 pod.go 中的 StreamPodLogs 函数 - 更新了相关引用和依赖 --- go.mod | 2 +- go.sum | 4 +- main.go | 8 +- pkg/callback/cb.go | 9 +- pkg/comm/kubectl/apply.go | 143 ------------- pkg/comm/kubectl/client.go | 87 +------- pkg/comm/kubectl/dynamic.go | 193 ----------------- pkg/comm/kubectl/dynamic_comm.go | 76 ------- pkg/comm/kubectl/dynamic_crd.go | 142 ------------- pkg/comm/kubectl/dynamic_gvr.go | 152 -------------- pkg/comm/kubectl/pod.go | 20 +- pkg/comm/kubectl/pod_file.go | 331 ------------------------------ pkg/controller/dynamic/dynamic.go | 9 +- pkg/controller/pod/pod.go | 6 +- pkg/controller/pod/pod_file.go | 62 +++--- 15 files changed, 51 insertions(+), 1193 deletions(-) delete mode 100644 pkg/comm/kubectl/apply.go delete mode 100644 pkg/comm/kubectl/dynamic.go delete mode 100644 pkg/comm/kubectl/dynamic_comm.go delete mode 100644 pkg/comm/kubectl/dynamic_crd.go delete mode 100644 pkg/comm/kubectl/dynamic_gvr.go delete mode 100644 pkg/comm/kubectl/pod_file.go diff --git a/go.mod b/go.mod index 6f7f3f6..0773cdb 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/gin-gonic/gin v1.10.0 github.com/sashabaranov/go-openai v1.32.2 github.com/spf13/pflag v1.0.5 - github.com/weibaohui/kom v0.0.4 + github.com/weibaohui/kom v0.0.9 k8s.io/api v0.31.1 k8s.io/apimachinery v0.31.1 k8s.io/client-go v0.31.1 diff --git a/go.sum b/go.sum index e2a2186..ba25a84 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/weibaohui/kom v0.0.4 h1:lspdv9C+6znaXkgLI5MCMgRcIqwDrfzr8LU+C0c/c5o= -github.com/weibaohui/kom v0.0.4/go.mod h1:8sFtcytn9hW16Ta/vPpt7SrP7AOgK+hhK4xqXO6t0Os= +github.com/weibaohui/kom v0.0.9 h1:Mvmgrh9YEP3iufqgi6yuZKY8PGM2YVr+5YrOmwf/pd8= +github.com/weibaohui/kom v0.0.9/go.mod h1:OauDGb387+wW44uGraJRVw+MYBWVjYrnAwdAX/5tqkM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/main.go b/main.go index 4280978..9ea7f8c 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,6 @@ import ( "github.com/gin-contrib/gzip" "github.com/gin-gonic/gin" "github.com/weibaohui/k8m/pkg/callback" - "github.com/weibaohui/k8m/pkg/comm/kubectl" "github.com/weibaohui/k8m/pkg/controller/chat" "github.com/weibaohui/k8m/pkg/controller/deploy" "github.com/weibaohui/k8m/pkg/controller/doc" @@ -18,7 +17,7 @@ import ( "github.com/weibaohui/k8m/pkg/controller/ns" "github.com/weibaohui/k8m/pkg/controller/pod" "github.com/weibaohui/k8m/pkg/flag" - "github.com/weibaohui/kom/starter" + "github.com/weibaohui/kom/kom_starter" "k8s.io/klog/v2" ) @@ -36,10 +35,7 @@ func Init() { klog.V(2).Infof("Git Commit: %s\n", GitCommit) // 初始化kom - starter.Init() - // 初始化kubectl 连接 - kubectl.InitConnection(cfg.KubeConfig) - + kom_starter.InitWithConfig(cfg.KubeConfig) // 初始化回调 callback.RegisterCallback() diff --git a/pkg/callback/cb.go b/pkg/callback/cb.go index dca3695..ba9b203 100644 --- a/pkg/callback/cb.go +++ b/pkg/callback/cb.go @@ -1,8 +1,6 @@ package callback import ( - "context" - "github.com/weibaohui/kom/kom" "k8s.io/klog/v2" ) @@ -12,10 +10,9 @@ func RegisterCallback() { _ = queryCallback.Register("k8m:get11", Get) } -func Get(ctx context.Context, k8s *kom.Kom) error { - json := k8s.Statement.String() +func Get(k8s *kom.Kom) error { // todo 在这里可以统一进行权限认证等操作,返回error即可阻断执行 - u := ctx.Value("user") - klog.V(2).Infof("%s k8s Get stmt json:\n %s\n", u, json) + u := k8s.Statement.Context.Value("user") + klog.V(2).Infof("%s k8s Get \n", u) return nil } diff --git a/pkg/comm/kubectl/apply.go b/pkg/comm/kubectl/apply.go deleted file mode 100644 index 3a5927b..0000000 --- a/pkg/comm/kubectl/apply.go +++ /dev/null @@ -1,143 +0,0 @@ -package kubectl - -import ( - "context" - "fmt" - "strings" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "sigs.k8s.io/yaml" -) - -// ApplyYAML 解析并应用 YAML 字符串到 Kubernetes -func (k8s *Kubectl) ApplyYAML(ctx context.Context, yamlStr string) (result []string) { - docs := splitYAML(yamlStr) - - for _, doc := range docs { - if strings.TrimSpace(doc) == "" { - continue - } - - // 解析 YAML 到 Unstructured 对象 - var obj unstructured.Unstructured - if err := yaml.Unmarshal([]byte(doc), &obj.Object); err != nil { - result = append(result, fmt.Sprintf("YAML 解析失败: %v", err)) - continue - } - - // 提取 Group, Version, Kind - gvk := obj.GroupVersionKind() - if gvk.Kind == "" || gvk.Version == "" { - result = append(result, fmt.Sprintf("YAML 缺少必要的 Group, Version 或 Kind")) - continue - } - - builtin := k8s.IsBuiltinResource(gvk.Kind) - if !builtin { - crd, err := k8s.GetCRD(ctx, gvk.Kind, gvk.Group) - if err != nil { - result = append(result, fmt.Sprintf("%v", err)) - } else { - crdResult := k8s.ApplyCRD(ctx, crd, &obj) - result = append(result, crdResult) - } - continue - - } - // 发现 string - kind := gvk.Kind - - // 获取命名空间 - ns := obj.GetNamespace() - if ns == "" && gvk.Kind != "Namespace" { - ns = "default" // 默认命名空间 - } - - // 使用 CreateOrUpdateResource 应用资源 - _, err := k8s.CreateResource(ctx, kind, ns, &obj) - if err != nil { - if errors.IsAlreadyExists(err) { - // 已经存在,更新 - existingResource, err := k8s.GetResource(ctx, kind, ns, obj.GetName()) - if err != nil { - result = append(result, fmt.Sprintf("获取应用失败%v", err.Error())) - continue - } - if existingResource != nil { - obj.SetResourceVersion(existingResource.GetResourceVersion()) - } - - _, err = k8s.UpdateResource(ctx, kind, ns, &obj) - if err != nil { - result = append(result, fmt.Sprintf("更新应用失败:%v", err.Error())) - continue - } - result = append(result, fmt.Sprintf("%s/%s updated", obj.GetKind(), obj.GetName())) - - } else { - result = append(result, fmt.Sprintf("创建应用失败:%s/%s,%s,%v\n", obj.GetKind(), obj.GetName(), kind, err.Error())) - continue - } - } else { - result = append(result, fmt.Sprintf("%s/%s created", obj.GetKind(), obj.GetName())) - } - - } - - return result -} -func (k8s *Kubectl) DeleteYAML(ctx context.Context, yamlStr string) (result []string) { - docs := splitYAML(yamlStr) - - for _, doc := range docs { - if strings.TrimSpace(doc) == "" { - continue - } - - // 解析 YAML 到 Unstructured 对象 - var obj unstructured.Unstructured - if err := yaml.Unmarshal([]byte(doc), &obj.Object); err != nil { - result = append(result, fmt.Sprintf("YAML 解析失败: %v", err)) - continue - } - - // 提取 Group, Version, Kind - gvk := obj.GroupVersionKind() - if gvk.Kind == "" || gvk.Version == "" { - result = append(result, fmt.Sprintf("YAML 缺少必要的 Group, Version 或 Kind")) - continue - } - - // 发现 string - builtIn := k8s.IsBuiltinResource(gvk.Kind) - if !builtIn { - // CRD 类型资源 - crd, err := k8s.GetCRD(ctx, gvk.Kind, gvk.Group) - if err != nil { - result = append(result, fmt.Sprintf("%v", err)) - } else { - // 确认为 CRD - crdResult := k8s.DeleteCRD(ctx, crd, &obj) - result = append(result, crdResult) - } - continue - } - - // 获取命名空间 - ns := obj.GetNamespace() - if ns == "" && gvk.Kind != "Namespace" { - ns = "default" // 默认命名空间 - } - - err := k8s.DeleteResource(ctx, gvk.Kind, ns, obj.GetName()) - if err != nil { - result = append(result, fmt.Sprintf("%s/%s deleted error:%v", obj.GetKind(), obj.GetName(), err)) - } else { - result = append(result, fmt.Sprintf("%s/%s deleted", obj.GetKind(), obj.GetName())) - } - - } - - return result -} diff --git a/pkg/comm/kubectl/client.go b/pkg/comm/kubectl/client.go index 88f0748..390a0bb 100644 --- a/pkg/comm/kubectl/client.go +++ b/pkg/comm/kubectl/client.go @@ -1,93 +1,8 @@ package kubectl -import ( - "strings" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/dynamic" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/klog/v2" -) - -var ( - kubectl *Kubectl -) -var apiResources []metav1.APIResource - type Kubectl struct { - client *kubernetes.Clientset - config *rest.Config - dynamicClient dynamic.Interface } func Init() *Kubectl { - return kubectl -} - -// InitConnection 在主入口处进行初始化 -func InitConnection(path string) { - klog.V(2).Infof("k8s client init") - kubectl = &Kubectl{} - - config, err := getKubeConfig(path) - if err != nil { - panic(err.Error()) - } - client, err := kubernetes.NewForConfig(config) - if err != nil { - panic(err.Error()) - } - - dynClient, err := dynamic.NewForConfig(config) - if err != nil { - panic(err.Error()) - } - - kubectl.client = client - kubectl.config = config - kubectl.dynamicClient = dynClient - _, lists, _ := kubectl.client.Discovery().ServerGroupsAndResources() - for _, list := range lists { - - resources := list.APIResources - version := list.GroupVersionKind().Version - group := list.GroupVersionKind().Group - groupVersion := list.GroupVersion - gvs := strings.Split(groupVersion, "/") - if len(gvs) == 2 { - group = gvs[0] - version = gvs[1] - } else { - // 只有version的情况"v1" - version = groupVersion - } - - for _, resource := range resources { - resource.Group = group - resource.Version = version - apiResources = append(apiResources, resource) - } - } - -} - -func getKubeConfig(path string) (*rest.Config, error) { - config, err := rest.InClusterConfig() - - if err != nil { - klog.V(2).Infof("尝试读取集群内访问配置:%v\n", err) - klog.V(2).Infof("尝试读取本地配置%s", path) - // 不是在集群中,读取参数配置 - config, err = clientcmd.BuildConfigFromFlags("", path) - if err != nil { - klog.Errorf(err.Error()) - } - - } - if config != nil { - klog.V(2).Infof("服务器地址:%s\n", config.Host) - } - return config, err + return &Kubectl{} } diff --git a/pkg/comm/kubectl/dynamic.go b/pkg/comm/kubectl/dynamic.go deleted file mode 100644 index f75a795..0000000 --- a/pkg/comm/kubectl/dynamic.go +++ /dev/null @@ -1,193 +0,0 @@ -package kubectl - -import ( - "context" - "fmt" - "sort" - "strings" - - "github.com/weibaohui/k8m/pkg/comm/utils" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/types" - "k8s.io/klog/v2" -) - -// ListOption Functional options for ListResources -type ListOption func(*metav1.ListOptions) - -// WithLabelSelector 设置 LabelSelector -func WithLabelSelector(labelSelector string) ListOption { - return func(lo *metav1.ListOptions) { - lo.LabelSelector = labelSelector - } -} - -// WithFieldSelector 设置 FieldSelector -func WithFieldSelector(fieldSelector string) ListOption { - return func(lo *metav1.ListOptions) { - lo.FieldSelector = fieldSelector - } -} - -func (k8s *Kubectl) ListResources(ctx context.Context, kind string, ns string, opts ...ListOption) ([]unstructured.Unstructured, error) { - gvr, namespaced := k8s.GetGVR(kind) - if gvr.Empty() { - return nil, fmt.Errorf("不支持的资源类型: %s", kind) - } - - listOptions := metav1.ListOptions{} - for _, opt := range opts { - opt(&listOptions) - } - - var err error - - var list *unstructured.UnstructuredList - if namespaced { - list, err = k8s.dynamicClient.Resource(gvr).Namespace(ns).List(ctx, listOptions) - } else { - list, err = k8s.dynamicClient.Resource(gvr).List(ctx, listOptions) - } - if err != nil { - return nil, err - } - var resources []unstructured.Unstructured - for _, item := range list.Items { - obj := item.DeepCopy() - k8s.RemoveManagedFields(obj) - resources = append(resources, *obj) - } - - return sortByCreationTime(resources), nil -} -func (k8s *Kubectl) GetResource(ctx context.Context, kind string, ns, name string) (*unstructured.Unstructured, error) { - gvr, namespaced := k8s.GetGVR(kind) - gvrString := utils.ToJSON(gvr) - klog.V(8).Infof("(k8s *Kubectl) GetResource GVR %s", gvrString) - if gvr.Empty() { - return nil, fmt.Errorf("不支持的资源类型: %s", kind) - } - var res *unstructured.Unstructured - var err error - - if namespaced { - res, err = k8s.dynamicClient.Resource(gvr).Namespace(ns).Get(ctx, name, metav1.GetOptions{}) - } else { - res, err = k8s.dynamicClient.Resource(gvr).Get(ctx, name, metav1.GetOptions{}) - } - if err != nil { - return nil, err - } - - k8s.RemoveManagedFields(res) - return res, nil -} -func (k8s *Kubectl) CreateResource(ctx context.Context, kind string, ns string, resource *unstructured.Unstructured) (*unstructured.Unstructured, error) { - gvr, namespaced := k8s.GetGVR(kind) - if gvr.Empty() { - return nil, fmt.Errorf("不支持的资源类型: %s", kind) - } - var createdResource *unstructured.Unstructured - var err error - - if namespaced { - createdResource, err = k8s.dynamicClient.Resource(gvr).Namespace(ns).Create(ctx, resource, metav1.CreateOptions{}) - } else { - createdResource, err = k8s.dynamicClient.Resource(gvr).Create(ctx, resource, metav1.CreateOptions{}) - } - if err != nil { - return nil, err - } - - k8s.RemoveManagedFields(createdResource) - return createdResource, nil -} - -func (k8s *Kubectl) UpdateResource(ctx context.Context, kind string, ns string, resource *unstructured.Unstructured) (*unstructured.Unstructured, error) { - gvr, namespaced := k8s.GetGVR(kind) - if gvr.Empty() { - return nil, fmt.Errorf("不支持的资源类型: %s", kind) - } - var updatedResource *unstructured.Unstructured - var err error - - if namespaced { - updatedResource, err = k8s.dynamicClient.Resource(gvr).Namespace(ns).Update(ctx, resource, metav1.UpdateOptions{}) - } else { - updatedResource, err = k8s.dynamicClient.Resource(gvr).Update(ctx, resource, metav1.UpdateOptions{}) - } - - if err != nil { - return nil, fmt.Errorf("无法更新资源: %v", err) - } - k8s.RemoveManagedFields(updatedResource) - return updatedResource, nil -} - -func (k8s *Kubectl) DeleteResource(ctx context.Context, kind string, ns, name string) error { - gvr, namespaced := k8s.GetGVR(kind) - if gvr.Empty() { - return fmt.Errorf("不支持的资源类型: %s", kind) - } - - if namespaced { - return k8s.dynamicClient.Resource(gvr).Namespace(ns).Delete(ctx, name, metav1.DeleteOptions{}) - } else { - return k8s.dynamicClient.Resource(gvr).Delete(ctx, name, metav1.DeleteOptions{}) - } -} - -func (k8s *Kubectl) PatchResource(ctx context.Context, kind string, ns, name string, patchType types.PatchType, patchData []byte) (*unstructured.Unstructured, error) { - gvr, namespaced := k8s.GetGVR(kind) - if gvr.Empty() { - return nil, fmt.Errorf("不支持的资源类型: %s", kind) - } - var obj *unstructured.Unstructured - var err error - - if namespaced { - obj, err = k8s.dynamicClient.Resource(gvr).Namespace(ns).Patch(ctx, name, patchType, patchData, metav1.PatchOptions{}) - } else { - obj, err = k8s.dynamicClient.Resource(gvr).Patch(ctx, name, patchType, patchData, metav1.PatchOptions{}) - } - if err != nil { - return nil, err - } - - k8s.RemoveManagedFields(obj) - return obj, nil -} - -// splitYAML 按 "---" 分割多文档 YAML -func splitYAML(yamlStr string) []string { - return strings.Split(yamlStr, "\n---\n") -} - -// RemoveManagedFields 删除 unstructured.Unstructured 对象中的 metadata.managedFields 字段 -func (k8s *Kubectl) RemoveManagedFields(obj *unstructured.Unstructured) { - // 获取 metadata - metadata, found, err := unstructured.NestedMap(obj.Object, "metadata") - if err != nil || !found { - return - } - - // 删除 managedFields - delete(metadata, "managedFields") - - // 更新 metadata - err = unstructured.SetNestedMap(obj.Object, metadata, "metadata") - if err != nil { - return - } -} - -// sortByCreationTime 按创建时间排序资源 -func sortByCreationTime(items []unstructured.Unstructured) []unstructured.Unstructured { - sort.Slice(items, func(i, j int) bool { - ti := items[i].GetCreationTimestamp() - tj := items[j].GetCreationTimestamp() - return ti.After(tj.Time) - }) - return items -} diff --git a/pkg/comm/kubectl/dynamic_comm.go b/pkg/comm/kubectl/dynamic_comm.go deleted file mode 100644 index 3d05357..0000000 --- a/pkg/comm/kubectl/dynamic_comm.go +++ /dev/null @@ -1,76 +0,0 @@ -package kubectl - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/yaml" -) - -func (k8s *Kubectl) ConvertUnstructuredToTypedObject(obj *unstructured.Unstructured, objType runtime.Object) error { - decoder := scheme.Codecs.UniversalDeserializer() - objBytes, err := obj.MarshalJSON() - if err != nil { - return fmt.Errorf("无法序列化 Unstructured 对象: %v", err) - } - - _, _, err = decoder.Decode(objBytes, nil, obj) - if err != nil { - return fmt.Errorf("无法将 Unstructured 解码为具体类型: %v", err) - } - return nil -} - -// ConvertToUnstructured 通用转换函数,将 runtime.Object 转换为 Unstructured -func (k8s *Kubectl) ConvertToUnstructured(obj interface{}) (*unstructured.Unstructured, error) { - // 使用 DefaultUnstructuredConverter 转换为 map - unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) - if err != nil { - return nil, err - } - - // 获取资源类型和版本信息 - gvk, err := GetGVK(obj) - if err != nil { - return nil, err - } - - // 创建 unstructured.Unstructured 对象并设置数据 - u := &unstructured.Unstructured{Object: unstructuredMap} - u.SetGroupVersionKind(gvk) - - return u, nil -} - -// GetGVK 获取对象的 GroupVersionKind -func GetGVK(obj interface{}) (schema.GroupVersionKind, error) { - switch o := obj.(type) { - case *unstructured.Unstructured: - return o.GroupVersionKind(), nil - case runtime.Object: - return o.GetObjectKind().GroupVersionKind(), nil - default: - return schema.GroupVersionKind{}, fmt.Errorf("不支持的类型%v", o) - } -} - -// ConvertUnstructuredToYAML 将 Unstructured 对象转换为 YAML 字符串 -func (k8s *Kubectl) ConvertUnstructuredToYAML(obj *unstructured.Unstructured) (string, error) { - - // Marshal Unstructured 对象为 JSON - jsonBytes, err := obj.MarshalJSON() - if err != nil { - return "", fmt.Errorf("无法序列化 Unstructured 对象为 JSON: %v", err) - } - - // 将 JSON 转换为 YAML - yamlBytes, err := yaml.JSONToYAML(jsonBytes) - if err != nil { - return "", fmt.Errorf("无法将 JSON 转换为 YAML: %v", err) - } - - return string(yamlBytes), nil -} diff --git a/pkg/comm/kubectl/dynamic_crd.go b/pkg/comm/kubectl/dynamic_crd.go deleted file mode 100644 index 615b806..0000000 --- a/pkg/comm/kubectl/dynamic_crd.go +++ /dev/null @@ -1,142 +0,0 @@ -package kubectl - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -func (k8s *Kubectl) FetchCRD(ctx context.Context, crd *unstructured.Unstructured, ns, name string) (*unstructured.Unstructured, error) { - gvr := k8s.getGRVFromCRD(crd) - // 检查CRD是否是Namespaced - isNamespaced := crd.Object["spec"].(map[string]interface{})["scope"].(string) == "Namespaced" - - if ns == "" && isNamespaced { - ns = "default" // 默认命名空间 - } - return k8s.GetResourceDynamic(ctx, gvr, isNamespaced, ns, name) -} -func (k8s *Kubectl) RemoveCRD(ctx context.Context, crd *unstructured.Unstructured, ns, name string) error { - gvr := k8s.getGRVFromCRD(crd) - // 检查CRD是否是Namespaced - isNamespaced := crd.Object["spec"].(map[string]interface{})["scope"].(string) == "Namespaced" - - if ns == "" && isNamespaced { - ns = "default" // 默认命名空间 - } - return k8s.RemoveResourceDynamic(ctx, gvr, isNamespaced, ns, name) -} -func (k8s *Kubectl) UpdateCRD(ctx context.Context, crd *unstructured.Unstructured, res *unstructured.Unstructured) (*unstructured.Unstructured, error) { - gvr := k8s.getGRVFromCRD(crd) - // 检查CRD是否是Namespaced - isNamespaced := crd.Object["spec"].(map[string]interface{})["scope"].(string) == "Namespaced" - - if res.GetNamespace() == "" && isNamespaced { - res.SetNamespace("default") // 默认命名空间 - } - return k8s.UpdateResourceDynamic(ctx, gvr, isNamespaced, res) -} -func (k8s *Kubectl) ListCRD(ctx context.Context, crd *unstructured.Unstructured, ns string) ([]unstructured.Unstructured, error) { - gvr := k8s.getGRVFromCRD(crd) - // 检查CRD是否是Namespaced - isNamespaced := crd.Object["spec"].(map[string]interface{})["scope"].(string) == "Namespaced" - - if ns == "" && isNamespaced { - ns = "default" // 默认命名空间 - } - return k8s.ListResourcesDynamic(ctx, gvr, isNamespaced, ns) -} - -func (k8s *Kubectl) GetCRD(ctx context.Context, kind string, group string) (*unstructured.Unstructured, error) { - crdList, err := k8s.ListResources(ctx, "CustomResourceDefinition", "") - if err != nil { - return nil, err - } - for _, crd := range crdList { - spec, found, err := unstructured.NestedMap(crd.Object, "spec") - if err != nil || !found { - continue - } - crdKind, found, err := unstructured.NestedString(spec, "names", "kind") - if err != nil || !found { - continue - } - crdGroup, found, err := unstructured.NestedString(spec, "group") - if err != nil || !found { - continue - } - if crdKind != kind || crdGroup != group { - continue - } - return &crd, nil - } - return nil, fmt.Errorf("crd %s.%s not found", kind, group) -} - -func (k8s *Kubectl) getGRVFromCRD(crd *unstructured.Unstructured) schema.GroupVersionResource { - // 提取 GVR - group := crd.Object["spec"].(map[string]interface{})["group"].(string) - version := crd.Object["spec"].(map[string]interface{})["versions"].([]interface{})[0].(map[string]interface{})["name"].(string) - resource := crd.Object["spec"].(map[string]interface{})["names"].(map[string]interface{})["plural"].(string) - - gvr := schema.GroupVersionResource{ - Group: group, - Version: version, - Resource: resource, - } - return gvr -} -func (k8s *Kubectl) DeleteCRD(ctx context.Context, crd *unstructured.Unstructured, obj *unstructured.Unstructured) (result string) { - gvr := k8s.getGRVFromCRD(crd) - // 检查CRD是否是Namespaced - isNamespaced := crd.Object["spec"].(map[string]interface{})["scope"].(string) == "Namespaced" - ns := obj.GetNamespace() - name := obj.GetName() - - if ns == "" && isNamespaced { - ns = "default" // 默认命名空间 - obj.SetNamespace(ns) - } - err := k8s.RemoveResourceDynamic(ctx, gvr, isNamespaced, ns, name) - if err != nil { - result = fmt.Sprintf("%s/%s deleted error:%v", obj.GetKind(), obj.GetName(), err) - } else { - result = fmt.Sprintf("%s/%s deleted", obj.GetKind(), obj.GetName()) - } - return result -} -func (k8s *Kubectl) ApplyCRD(ctx context.Context, crd *unstructured.Unstructured, obj *unstructured.Unstructured) (result string) { - gvr := k8s.getGRVFromCRD(crd) - // 检查CRD是否是Namespaced - isNamespaced := crd.Object["spec"].(map[string]interface{})["scope"].(string) == "Namespaced" - ns := obj.GetNamespace() - name := obj.GetName() - kind := obj.GetKind() - - if ns == "" && isNamespaced { - ns = "default" // 默认命名空间 - obj.SetNamespace(ns) - } - exist, err := k8s.GetResourceDynamic(ctx, gvr, isNamespaced, ns, name) - if err == nil && exist != nil && exist.GetName() != "" { - // 已经存在资源,那么就更新 - obj.SetResourceVersion(exist.GetResourceVersion()) - _, err := k8s.UpdateResourceDynamic(ctx, gvr, isNamespaced, obj) - if err != nil { - result = fmt.Sprintf("更新CRD应用失败:%v", err.Error()) - return result - } - result = fmt.Sprintf("%s/%s updated", kind, name) - } else { - // 不存在,那么就创建 - _, err := k8s.CreateResourceDynamic(ctx, gvr, isNamespaced, obj) - if err != nil { - result = fmt.Sprintf("创建CRD应用失败:%v %s/%s %v", err.Error(), gvr.GroupResource(), name, isNamespaced) - return result - } - result = fmt.Sprintf("%s/%s created", kind, name) - } - return result -} diff --git a/pkg/comm/kubectl/dynamic_gvr.go b/pkg/comm/kubectl/dynamic_gvr.go deleted file mode 100644 index dea8dab..0000000 --- a/pkg/comm/kubectl/dynamic_gvr.go +++ /dev/null @@ -1,152 +0,0 @@ -package kubectl - -import ( - "context" - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" -) - -func (k8s *Kubectl) ListResourcesDynamic(ctx context.Context, gvr schema.GroupVersionResource, isNamespaced bool, ns string, opts ...ListOption) ([]unstructured.Unstructured, error) { - if gvr.Empty() { - return nil, fmt.Errorf("GroupVersionResource is empty") - } - - listOptions := metav1.ListOptions{} - for _, opt := range opts { - opt(&listOptions) - } - var list *unstructured.UnstructuredList - var err error - if isNamespaced { - list, err = k8s.dynamicClient.Resource(gvr).Namespace(ns).List(ctx, listOptions) - } else { - list, err = k8s.dynamicClient.Resource(gvr).List(ctx, listOptions) - } - if err != nil { - return nil, err - } - var resources []unstructured.Unstructured - for _, item := range list.Items { - obj := item.DeepCopy() - k8s.RemoveManagedFields(obj) - resources = append(resources, *obj) - } - - return sortByCreationTime(resources), nil -} -func (k8s *Kubectl) GetResourceDynamic(ctx context.Context, gvr schema.GroupVersionResource, isNamespaced bool, ns, name string) (*unstructured.Unstructured, error) { - if gvr.Empty() { - return nil, fmt.Errorf("GroupVersionResource is empty") - } - var obj *unstructured.Unstructured - var err error - if isNamespaced { - obj, err = k8s.dynamicClient.Resource(gvr).Namespace(ns).Get(ctx, name, metav1.GetOptions{}) - } else { - obj, err = k8s.dynamicClient.Resource(gvr).Get(ctx, name, metav1.GetOptions{}) - } - if err != nil { - return nil, err - } - - k8s.RemoveManagedFields(obj) - return obj, nil -} -func (k8s *Kubectl) CreateResourceDynamic(ctx context.Context, gvr schema.GroupVersionResource, isNamespaced bool, resource *unstructured.Unstructured) (*unstructured.Unstructured, error) { - if gvr.Empty() { - return nil, fmt.Errorf("GroupVersionResource is empty") - } - var createdResource *unstructured.Unstructured - var err error - if isNamespaced { - createdResource, err = k8s.dynamicClient.Resource(gvr).Namespace(resource.GetNamespace()).Create(ctx, resource, metav1.CreateOptions{}) - } else { - createdResource, err = k8s.dynamicClient.Resource(gvr).Create(ctx, resource, metav1.CreateOptions{}) - } - if err != nil { - return nil, err - } - - k8s.RemoveManagedFields(createdResource) - return createdResource, nil -} - -func (k8s *Kubectl) RemoveResourceDynamic(ctx context.Context, gvr schema.GroupVersionResource, isNamespaced bool, ns, name string) error { - if gvr.Empty() { - return fmt.Errorf("GroupVersionResource is empty") - } - if isNamespaced { - return k8s.dynamicClient.Resource(gvr).Namespace(ns).Delete(ctx, name, metav1.DeleteOptions{}) - } else { - return k8s.dynamicClient.Resource(gvr).Delete(ctx, name, metav1.DeleteOptions{}) - } -} - -func (k8s *Kubectl) PatchResourceDynamic(ctx context.Context, gvr schema.GroupVersionResource, isNamespaced bool, ns, name string, patchType types.PatchType, patchData []byte) (*unstructured.Unstructured, error) { - if gvr.Empty() { - return nil, fmt.Errorf("GroupVersionResource is empty") - } - var obj *unstructured.Unstructured - var err error - if isNamespaced { - obj, err = k8s.dynamicClient.Resource(gvr).Namespace(ns).Patch(ctx, name, patchType, patchData, metav1.PatchOptions{}) - } else { - obj, err = k8s.dynamicClient.Resource(gvr).Patch(ctx, name, patchType, patchData, metav1.PatchOptions{}) - } - if err != nil { - return nil, err - } - - k8s.RemoveManagedFields(obj) - return obj, nil -} -func (k8s *Kubectl) UpdateResourceDynamic(ctx context.Context, gvr schema.GroupVersionResource, isNamespaced bool, resource *unstructured.Unstructured) (*unstructured.Unstructured, error) { - if gvr.Empty() { - return nil, fmt.Errorf("GroupVersionResource is empty") - } - var updatedResource *unstructured.Unstructured - var err error - if isNamespaced { - updatedResource, err = k8s.dynamicClient.Resource(gvr).Namespace(resource.GetNamespace()).Update(ctx, resource, metav1.UpdateOptions{}) - - } else { - updatedResource, err = k8s.dynamicClient.Resource(gvr).Update(ctx, resource, metav1.UpdateOptions{}) - } - - if err != nil { - return nil, fmt.Errorf("无法更新资源: %v", err) - } - k8s.RemoveManagedFields(updatedResource) - return updatedResource, nil -} - -// GetGVR 返回对应 string 的 GroupVersionResource -// 从k8s API接口中获取的值 -// 如果同时存在多个version,则返回第一个 -// 因此也有可能version不对 -func (k8s *Kubectl) GetGVR(kind string) (gvr schema.GroupVersionResource, namespaced bool) { - for _, resource := range apiResources { - if resource.Kind == kind { - version := resource.Version - gvr = schema.GroupVersionResource{ - Group: resource.Group, - Version: version, - Resource: resource.Name, // 通常是 Kind 的复数形式 - } - return gvr, resource.Namespaced - } - } - return schema.GroupVersionResource{}, false -} -func (k8s *Kubectl) IsBuiltinResource(kind string) bool { - for _, list := range apiResources { - if list.Kind == kind { - return true - } - } - return false -} diff --git a/pkg/comm/kubectl/pod.go b/pkg/comm/kubectl/pod.go index ad163a5..07d122f 100644 --- a/pkg/comm/kubectl/pod.go +++ b/pkg/comm/kubectl/pod.go @@ -3,10 +3,9 @@ package kubectl import ( "context" "io" - "sort" + "github.com/weibaohui/kom/kom/poder" v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func (k8s *Kubectl) StreamPodLogs(ctx context.Context, ns, name string, logOptions *v1.PodLogOptions) (io.ReadCloser, error) { @@ -20,24 +19,9 @@ func (k8s *Kubectl) StreamPodLogs(ctx context.Context, ns, name string, logOptio if logOptions.SinceSeconds != nil && *logOptions.SinceSeconds == 0 { logOptions.SinceSeconds = nil } - // json := &utils.JSONUtils{} - // klog.V(2).Infof(json.ToJSON(logOptions)) - // 获取 Pod 日志 - podLogs := k8s.client.CoreV1().Pods(ns).GetLogs(name, logOptions) + podLogs := poder.Instance().WithContext(ctx).Namespace(ns).Name(name).GetLogs(name, logOptions) logStream, err := podLogs.Stream(ctx) return logStream, err } - -// ListPodByLabelSelector key1=value1,key2=value2 -func (k8s *Kubectl) ListPodByLabelSelector(ctx context.Context, ns, selector string) ([]v1.Pod, error) { - list, err := k8s.client.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{LabelSelector: selector}) - if err == nil && list != nil && list.Items != nil && len(list.Items) > 0 { - sort.Slice(list.Items, func(i, j int) bool { - return list.Items[i].CreationTimestamp.Time.After(list.Items[j].CreationTimestamp.Time) - }) - return list.Items, nil - } - return nil, err -} diff --git a/pkg/comm/kubectl/pod_file.go b/pkg/comm/kubectl/pod_file.go deleted file mode 100644 index 2d3fd0d..0000000 --- a/pkg/comm/kubectl/pod_file.go +++ /dev/null @@ -1,331 +0,0 @@ -package kubectl - -import ( - "bytes" - "fmt" - "io" - "mime/multipart" - "os" - "strings" - - "github.com/weibaohui/k8m/pkg/comm/utils" - "k8s.io/client-go/tools/remotecommand" - "k8s.io/klog/v2" -) - -// PodFileNode 文件节点结构 -type PodFileNode struct { - Name string `json:"name"` - Type string `json:"type"` // file or directory - Permissions string `json:"permissions"` - Size int64 `json:"size"` - ModTime string `json:"modTime"` - Path string `json:"path"` // 存储路径 - IsDir bool `json:"isDir"` // 指示是否 -} - -// PodFileInfo 应用配置结构 -type PodFileInfo struct { - Namespace string - PodName string - ContainerName string -} - -// GetFileList 获取容器中指定路径的文件和目录列表 -func (p *PodFileInfo) GetFileList(path string) ([]*PodFileNode, error) { - cmd := []string{"ls", "-l", path} - req := kubectl.client.CoreV1().RESTClient(). - Get(). - Namespace(p.Namespace). - Resource("pods"). - Name(p.PodName). - SubResource("exec"). - Param("container", p.ContainerName). - Param("command", cmd[0]). - Param("command", cmd[1]). - Param("command", cmd[2]). - Param("tty", "false"). - Param("stdin", "false"). - Param("stdout", "true"). - Param("stderr", "true") - - executor, err := remotecommand.NewSPDYExecutor(kubectl.config, "POST", req.URL()) - if err != nil { - return nil, fmt.Errorf("error creating executor: %v", err) - } - - var stdout bytes.Buffer - err = executor.Stream(remotecommand.StreamOptions{ - Stdout: &stdout, - Stderr: os.Stderr, - }) - - if err != nil { - return nil, fmt.Errorf("error executing command: %v", err) - } - - return p.parseFileList(path, stdout.String()), nil -} - -// DownloadFile 从指定容器下载文件 -func (p *PodFileInfo) DownloadFile(filePath string) ([]byte, error) { - cmd := []string{"cat", filePath} - klog.V(8).Infof("DownloadFile %s", filePath) - - req := kubectl.client.CoreV1().RESTClient(). - Get(). - Namespace(p.Namespace). - Resource("pods"). - Name(p.PodName). - SubResource("exec"). - Param("container", p.ContainerName). - Param("command", cmd[0]). - Param("command", cmd[1]). - Param("tty", "false"). - Param("stdin", "false"). - Param("stdout", "true"). - Param("stderr", "true") - - executor, err := remotecommand.NewSPDYExecutor(kubectl.config, "POST", req.URL()) - if err != nil { - return nil, fmt.Errorf("error creating executor: %v", err) - } - - var stdout bytes.Buffer - var stderr bytes.Buffer - err = executor.Stream(remotecommand.StreamOptions{ - Stdout: &stdout, - Stderr: &stderr, - }) - - if err != nil { - s := stderr.String() - if strings.Contains(s, "Invalid argument") { - return nil, fmt.Errorf("系统参数错误 %v", s) - } - return nil, fmt.Errorf("error executing command: %v %v", err, s) - } - - return stdout.Bytes(), nil -} - -// UploadFile 将文件上传到指定容器 -func (p *PodFileInfo) UploadFile(destPath string, file multipart.File) error { - // 创建临时文件 - tempFile, err := os.CreateTemp("", "upload-*") - if err != nil { - return fmt.Errorf("error creating temp file: %v", err) - } - defer func(name string) { - err := os.Remove(name) - if err != nil { - klog.V(6).Infof("remve %s error:%v", name, err) - } - }(tempFile.Name()) // 确保临时文件在函数结束时被删除 - - // 将上传的文件内容写入临时文件 - _, err = io.Copy(tempFile, file) - if err != nil { - return fmt.Errorf("error writing to temp file: %v", err) - } - - // 确保文件关闭 - if err := tempFile.Close(); err != nil { - return fmt.Errorf("error closing temp file: %v", err) - } - - cmd := []string{"sh", "-c", fmt.Sprintf("cat > %s", destPath)} - - req := kubectl.client.CoreV1().RESTClient(). - Post(). - Namespace(p.Namespace). - Resource("pods"). - Name(p.PodName). - SubResource("exec"). - Param("container", p.ContainerName). - Param("tty", "false"). - Param("command", cmd[0]). - Param("command", cmd[1]). - Param("command", cmd[2]). - Param("stdin", "true"). - Param("stdout", "true"). - Param("stderr", "true") - - executor, err := remotecommand.NewSPDYExecutor(kubectl.config, "POST", req.URL()) - if err != nil { - return fmt.Errorf("error creating executor: %v", err) - } - - // 打开本地文件进行传输 - readFile, err := os.Open(tempFile.Name()) - if err != nil { - return fmt.Errorf("error opening file: %v", err) - } - defer func(readFile *os.File) { - err := readFile.Close() - if err != nil { - klog.V(6).Infof("readFile.Close() error:%v", err) - } - }(readFile) - var stdout, stderr bytes.Buffer - err = executor.Stream(remotecommand.StreamOptions{ - Stdin: readFile, - Stdout: &stdout, - Stderr: &stderr, - }) - - if err != nil { - return fmt.Errorf("error executing command: %v: %s", err, stderr.String()) - } - - return nil -} - -func (p *PodFileInfo) SaveFile(path string, context string) error { - - // 创建临时文件 - tempFile, err := os.CreateTemp("", "upload-*") - if err != nil { - return fmt.Errorf("error creating temp file: %v", err) - } - defer func(name string) { - err := os.Remove(name) - if err != nil { - klog.V(6).Infof("remve %s error:%v", name, err) - } - }(tempFile.Name()) // 确保临时文件在函数结束时被删除 - - // 将上传的文件内容写入临时文件 - _, err = io.WriteString(tempFile, context) - if err != nil { - return fmt.Errorf("error writing to temp file: %v", err) - } - - // 确保文件关闭 - if err := tempFile.Close(); err != nil { - return fmt.Errorf("error closing temp file: %v", err) - } - - cmd := []string{"sh", "-c", fmt.Sprintf("cat > %s", path)} - - req := kubectl.client.CoreV1().RESTClient(). - Post(). - Namespace(p.Namespace). - Resource("pods"). - Name(p.PodName). - SubResource("exec"). - Param("container", p.ContainerName). - Param("tty", "false"). - Param("command", cmd[0]). - Param("command", cmd[1]). - Param("command", cmd[2]). - Param("stdin", "true"). - Param("stdout", "true"). - Param("stderr", "true") - - executor, err := remotecommand.NewSPDYExecutor(kubectl.config, "POST", req.URL()) - if err != nil { - return fmt.Errorf("error creating executor: %v", err) - } - - // 打开本地文件进行传输 - file, err := os.Open(tempFile.Name()) - if err != nil { - return fmt.Errorf("error opening file: %v", err) - } - defer func(file *os.File) { - err := file.Close() - if err != nil { - klog.V(6).Infof("file.Close() error:%v", err) - } - }(file) - var stdout, stderr bytes.Buffer - err = executor.Stream(remotecommand.StreamOptions{ - Stdin: file, - Stdout: &stdout, - Stderr: &stderr, - }) - - if err != nil { - return fmt.Errorf("error executing command: %v: %s", err, stderr.String()) - } - - return nil -} - -// getFileType 根据文件权限获取文件类型 -// -// l 代表符号链接(Symbolic link) -// - 代表普通文件(Regular file) -// d 代表目录(Directory) -// b 代表块设备(Block device) -// c 代表字符设备(Character device) -// p 代表命名管道(Named pipe) -// s 代表套接字(Socket) -func getFileType(permissions string) string { - // 获取文件类型标志位 - p := permissions[0] - var fileType string - - switch p { - case 'd': - fileType = "directory" // 目录 - case '-': - fileType = "file" // 普通文件 - case 'l': - fileType = "link" // 符号链接 - case 'b': - fileType = "block" // 块设备 - case 'c': - fileType = "character" // 字符设备 - case 'p': - fileType = "pipe" // 命名管道 - case 's': - fileType = "socket" // 套接字 - default: - fileType = "unknown" // 未知类型 - } - - return fileType -} - -// parseFileList 解析输出并生成 PodFileNode 列表 -func (p *PodFileInfo) parseFileList(path, output string) []*PodFileNode { - var nodes []*PodFileNode - lines := strings.Split(output, "\n") - for _, line := range lines { - if line == "" { - continue - } - parts := strings.Fields(line) - if len(parts) < 9 { - continue // 不完整的行 - } - - permissions := parts[0] - name := parts[8] - size := parts[4] - modTime := strings.Join(parts[5:8], " ") - - // 判断文件类型 - - fileType := getFileType(permissions) - - // 封装成 PodFileNode - node := PodFileNode{ - Path: fmt.Sprintf("/%s", name), - Name: name, - Type: fileType, - Permissions: permissions, - Size: utils.ToInt64(size), - ModTime: modTime, - IsDir: fileType == "directory", - } - if path != "/" { - node.Path = fmt.Sprintf("%s/%s", path, name) - } - nodes = append(nodes, &node) - } - - return nodes -} diff --git a/pkg/controller/dynamic/dynamic.go b/pkg/controller/dynamic/dynamic.go index 9868110..063c1e0 100644 --- a/pkg/controller/dynamic/dynamic.go +++ b/pkg/controller/dynamic/dynamic.go @@ -4,9 +4,10 @@ import ( "context" "github.com/gin-gonic/gin" - "github.com/weibaohui/k8m/pkg/comm/kubectl" "github.com/weibaohui/k8m/pkg/comm/utils/amis" "github.com/weibaohui/kom/kom" + "github.com/weibaohui/kom/kom/applier" + "github.com/weibaohui/kom/utils" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/yaml" ) @@ -35,7 +36,7 @@ func Fetch(c *gin.Context) { return } - yamlStr, err := kubectl.Init().ConvertUnstructuredToYAML(obj) + yamlStr, err := utils.ConvertUnstructuredToYAML(obj) if err != nil { amis.WriteJsonError(c, err) return @@ -133,7 +134,7 @@ func Apply(c *gin.Context) { return } yamlStr := req.YAML - result := kubectl.Init().ApplyYAML(ctx, yamlStr) + result := applier.Instance().WithContext(ctx).Apply(yamlStr) amis.WriteJsonData(c, gin.H{ "result": result, }) @@ -149,7 +150,7 @@ func Delete(c *gin.Context) { return } yamlStr := req.YAML - result := kubectl.Init().DeleteYAML(ctx, yamlStr) + result := applier.Instance().WithContext(ctx).Delete(yamlStr) amis.WriteJsonData(c, gin.H{ "result": result, }) diff --git a/pkg/controller/pod/pod.go b/pkg/controller/pod/pod.go index b6497b1..c398ae2 100644 --- a/pkg/controller/pod/pod.go +++ b/pkg/controller/pod/pod.go @@ -19,7 +19,9 @@ func StreamLogs(c *gin.Context) { var podName = c.Param("pod_name") var containerName = c.Param("container_name") selector := fmt.Sprintf("metadata.name=%s", podName) - StreamPodLogsBySelector(c, ns, containerName, metav1.ListOptions{LabelSelector: selector}) + StreamPodLogsBySelector(c, ns, containerName, metav1.ListOptions{ + FieldSelector: selector, + }) } func StreamPodLogsBySelector(c *gin.Context, ns string, containerName string, options metav1.ListOptions) { ctx := c.Request.Context() @@ -55,7 +57,7 @@ func DownloadLogs(c *gin.Context) { var podName = c.Param("pod_name") var containerName = c.Param("container_name") selector := fmt.Sprintf("metadata.name=%s", podName) - DownloadPodLogsBySelector(c, ns, containerName, metav1.ListOptions{LabelSelector: selector}) + DownloadPodLogsBySelector(c, ns, containerName, metav1.ListOptions{FieldSelector: selector}) } func DownloadPodLogsBySelector(c *gin.Context, ns string, containerName string, options metav1.ListOptions) { ctx := c.Request.Context() diff --git a/pkg/controller/pod/pod_file.go b/pkg/controller/pod/pod_file.go index c1f2543..53a2de6 100644 --- a/pkg/controller/pod/pod_file.go +++ b/pkg/controller/pod/pod_file.go @@ -6,9 +6,9 @@ import ( "path/filepath" "github.com/gin-gonic/gin" - "github.com/weibaohui/k8m/pkg/comm/kubectl" "github.com/weibaohui/k8m/pkg/comm/utils" "github.com/weibaohui/k8m/pkg/comm/utils/amis" + "github.com/weibaohui/kom/kom/poder" "k8s.io/klog/v2" ) @@ -33,17 +33,17 @@ func FileList(c *gin.Context) { return } - pf := kubectl.PodFileInfo{ - Namespace: info.Namespace, - PodName: info.PodName, - ContainerName: info.ContainerName, - } + poder := poder.Instance(). + WithContext(c.Request.Context()). + Namespace(info.Namespace). + Name(info.PodName). + ContainerName(info.ContainerName) if info.Path == "" { info.Path = "/" } // 获取文件列表 - nodes, err := pf.GetFileList(info.Path) + nodes, err := poder.GetFileList(info.Path) if err != nil { amis.WriteJsonError(c, fmt.Errorf("获取文件列表失败,容器内没有shell或者没有ls命令")) return @@ -60,11 +60,11 @@ func ShowFile(c *gin.Context) { return } - pf := kubectl.PodFileInfo{ - Namespace: info.Namespace, - PodName: info.PodName, - ContainerName: info.ContainerName, - } + poder := poder.Instance(). + WithContext(c.Request.Context()). + Namespace(info.Namespace). + Name(info.PodName). + ContainerName(info.ContainerName) if info.FileType != "" && info.FileType != "file" && info.FileType != "directory" { amis.WriteJsonError(c, fmt.Errorf("无法查看%s类型文件", info.FileType)) return @@ -79,7 +79,7 @@ func ShowFile(c *gin.Context) { } // 从容器中下载文件 - fileContent, err := pf.DownloadFile(info.Path) + fileContent, err := poder.DownloadFile(info.Path) if err != nil { amis.WriteJsonError(c, err) return @@ -106,11 +106,11 @@ func SaveFile(c *gin.Context) { return } - pf := kubectl.PodFileInfo{ - Namespace: info.Namespace, - PodName: info.PodName, - ContainerName: info.ContainerName, - } + poder := poder.Instance(). + WithContext(c.Request.Context()). + Namespace(info.Namespace). + Name(info.PodName). + ContainerName(info.ContainerName) if info.Path == "" { amis.WriteJsonOK(c) @@ -127,7 +127,7 @@ func SaveFile(c *gin.Context) { return } // 上传文件 - if err := pf.SaveFile(info.Path, context); err != nil { + if err := poder.SaveFile(info.Path, context); err != nil { klog.V(2).Infof("Error uploading file: %v", err) amis.WriteJsonError(c, err) return @@ -145,13 +145,13 @@ func DownloadFile(c *gin.Context) { return } - pf := kubectl.PodFileInfo{ - Namespace: info.Namespace, - PodName: info.PodName, - ContainerName: info.ContainerName, - } + poder := poder.Instance(). + WithContext(c.Request.Context()). + Namespace(info.Namespace). + Name(info.PodName). + ContainerName(info.ContainerName) // 从容器中下载文件 - fileContent, err := pf.DownloadFile(info.Path) + fileContent, err := poder.DownloadFile(info.Path) if err != nil { klog.V(2).Infof("Error downloading file: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) @@ -184,11 +184,11 @@ func UploadFile(c *gin.Context) { // 替换FileName中非法字符 info.FileName = utils.SanitizeFileName(info.FileName) - pf := kubectl.PodFileInfo{ - Namespace: info.Namespace, - PodName: info.PodName, - ContainerName: info.ContainerName, - } + poder := poder.Instance(). + WithContext(c.Request.Context()). + Namespace(info.Namespace). + Name(info.PodName). + ContainerName(info.ContainerName) // 获取上传的文件 file, _, err := c.Request.FormFile("file") @@ -202,7 +202,7 @@ func UploadFile(c *gin.Context) { savePath := fmt.Sprintf("%s/%s", info.Path, info.FileName) // klog.V(2).Infof("存储文件路径%s", savePath) // 上传文件 - if err := pf.UploadFile(savePath, file); err != nil { + if err := poder.UploadFile(savePath, file); err != nil { klog.V(2).Infof("Error uploading file: %v", err) amis.WriteJsonError(c, err) return