From 640ba209c1955cb7c341d1b7cdfc43aaeddcdea2 Mon Sep 17 00:00:00 2001 From: lflxp <382023823@qq.com> Date: Thu, 1 Feb 2024 20:05:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0smkubectl=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 8 +- go.sum | 16 +-- .../github.com/lflxp/smkubectl/cmd/smart.go | 4 + .../lflxp/smkubectl/cmd/smkubectl.go | 110 ++++++++++++++-- .../lflxp/smkubectl/completion/kill.go | 63 ++++++++- .../lflxp/smkubectl/completion/showme.go | 23 +++- .../github.com/lflxp/smkubectl/utils/cache.go | 121 ++++++++++++++++++ vendor/modules.txt | 9 +- 8 files changed, 322 insertions(+), 32 deletions(-) create mode 100644 vendor/github.com/lflxp/smkubectl/utils/cache.go diff --git a/go.mod b/go.mod index c1ae7863..0c5b1d33 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/lflxp/lflxp-sflowtool v0.0.0-20200323103145-8e12626667ee github.com/lflxp/lflxp-static v1.0.3 github.com/lflxp/lflxp-tty v1.0.1 - github.com/lflxp/smkubectl v0.1.3 + github.com/lflxp/smkubectl v0.1.6 github.com/lithammer/fuzzysearch v1.1.5 github.com/mattn/go-runewidth v0.0.14 github.com/mattn/go-sqlite3 v2.0.3+incompatible @@ -49,7 +49,7 @@ require ( github.com/ugorji/go/codec v1.2.11 github.com/ying32/govcl v2.2.0+incompatible golang.org/x/term v0.16.0 - k8s.io/client-go v0.29.0 + k8s.io/client-go v0.29.1 ) require ( @@ -221,8 +221,8 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v1.0.0 // indirect - k8s.io/api v0.29.0 // indirect - k8s.io/apimachinery v0.29.0 // indirect + k8s.io/api v0.29.1 // indirect + k8s.io/apimachinery v0.29.1 // indirect k8s.io/klog/v2 v2.110.1 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect k8s.io/metrics v0.29.0 // indirect diff --git a/go.sum b/go.sum index 05721d67..b1752ca1 100644 --- a/go.sum +++ b/go.sum @@ -650,8 +650,8 @@ github.com/lflxp/lflxp-static v1.0.3/go.mod h1:aQMJHATJybwd+2GlJEEECKIxROGxFybIW github.com/lflxp/lflxp-tty v1.0.1 h1:Lvphf8Sa/3Oc2O2/vih6MD1oKb1PU68XsSmi59abpJY= github.com/lflxp/lflxp-tty v1.0.1/go.mod h1:FztgAiLI4LAipR2jtmTvDSlb3SOLbWGuikZsBnxnL58= github.com/lflxp/sflowtool v0.0.0-20200320153314-630933f4918a/go.mod h1:eHScap6gPi9BndOq7P2dLGiZAcbzae2pnh77z3G+t9I= -github.com/lflxp/smkubectl v0.1.3 h1:lIdgiiQ9FHPzKS9luPk3PFby+XQPeldZRrI8LO+RN2I= -github.com/lflxp/smkubectl v0.1.3/go.mod h1:eKTv0oOq8hqGCmWEgLy6gsJKT3SyjrfBEzCXLuYPnbc= +github.com/lflxp/smkubectl v0.1.6 h1:n30phjSsYsWk3yL4CL+a8ObJPKpVxQlDEu9Tu7XBLwM= +github.com/lflxp/smkubectl v0.1.6/go.mod h1:8Tu2E3SrHe7wTez4mf6E8ztFo9BHcjbN7L2kSRoGxjg= github.com/lflxp/tools v0.0.11 h1:SJr6R8Vw/zNdq6kVRfvHKpvajzXowzY+brWfSP+an3A= github.com/lflxp/tools v0.0.11/go.mod h1:7cokwzc5mWIQVUxZ53TWmU2Nksd5+G6Qx+729FrfrMU= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -1614,14 +1614,14 @@ howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCU howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= k8s.io/api v0.0.0-20180428142247-b7d77fa220f5/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= -k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= +k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw= +k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ= k8s.io/apimachinery v0.0.0-20180503031313-e7cad760a93d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= -k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= +k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= +k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= k8s.io/client-go v0.0.0-20180501182648-01d6a1350dd5/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= +k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A= +k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= diff --git a/vendor/github.com/lflxp/smkubectl/cmd/smart.go b/vendor/github.com/lflxp/smkubectl/cmd/smart.go index 89c56a0f..ff0bd7ff 100644 --- a/vendor/github.com/lflxp/smkubectl/cmd/smart.go +++ b/vendor/github.com/lflxp/smkubectl/cmd/smart.go @@ -12,6 +12,9 @@ import ( var debugLevel bool +// zsh kubectl api-resources固定配置 +var fast bool + // smartCmd represents the smart command var smartCmd = &cobra.Command{ Use: "smart", @@ -45,4 +48,5 @@ func init() { // is called directly, e.g.: // smartCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") smartCmd.Flags().BoolVarP(&debugLevel, "debug", "d", false, "Log Level") + smartCmd.Flags().BoolVarP(&fast, "fast", "f", false, "是否开启快速api-resources对齐") } diff --git a/vendor/github.com/lflxp/smkubectl/cmd/smkubectl.go b/vendor/github.com/lflxp/smkubectl/cmd/smkubectl.go index 5e75adfd..cfa7420a 100644 --- a/vendor/github.com/lflxp/smkubectl/cmd/smkubectl.go +++ b/vendor/github.com/lflxp/smkubectl/cmd/smkubectl.go @@ -10,6 +10,7 @@ import ( "strings" . "github.com/lflxp/smkubectl/completion" + "github.com/lflxp/smkubectl/utils" ) func ContainsString(slice []string, s string) bool { @@ -74,7 +75,7 @@ func ParseCmd(in string) { slog.Error(err.Error()) return } - fmt.Printf(strings.Join(rs, "\n")) + fmt.Printf("%s", strings.Join(rs, "\n")) } else { // 根据命令长度智能补全命令 if len(result) == 2 { @@ -100,7 +101,7 @@ func ParseCmd(in string) { t_one = append(t_one, strings.Replace(k, result[1], "", 1)) } } - fmt.Printf(strings.Join(t_one, "\n")) + fmt.Printf("%s", strings.Join(t_one, "\n")) } else if len(result) == 3 && !isLastWorkSpace { // 补全命令 slog.Debug("智能补全三级命令") @@ -112,7 +113,7 @@ func ParseCmd(in string) { return } } - fmt.Printf(strings.Join(t_two, "\n")) + fmt.Printf("%s", strings.Join(t_two, "\n")) } else { // 补全数据 slog.Debug("智能补全多级命令") @@ -124,20 +125,105 @@ func ParseCmd(in string) { // 补全实时数据结果 // 补全数据 有空格 // 如果获取最后一个参数无数据 则执行该命令 - slog.Debug("补全实时数据结果", "命令是否包含空格", isLastWorkSpace) + slog.Debug("补全实时数据结果", "命令是否包含空格", isLastWorkSpace, "FAST", fast) var cmd string switch result[0] { case "kubectl", "k", "kk", "k8s": // 判断最后一个参数是否是命令行参数 isCmds := false - // TODO: 查询速度慢 简写无法处理 - // 要去kubectl api-resources结果中获取 - for _, c := range value.Cmd { - if strings.HasPrefix(c, result[len(result)-1]) { - cmd = fmt.Sprintf("kubectl get %s -A", result[len(result)-1]) - isCmds = true - break + + if fast { + // 固定配置 + // 优点:查询快 + // 缺点:不能实时匹配 + slog.Debug("启动FAST固定配置", "TYPE", "KUBECTL API-RESOURCES") + for _, c := range value.Daughter["get"].Cmd { + if strings.HasPrefix(c, result[len(result)-1]) { + cmd = fmt.Sprintf("kubectl get %s -A", result[len(result)-1]) + isCmds = true + break + } + } + } else { + // 缓存文件解决查询速度问题 + cacheData, err := utils.ReadYamlToStruct() + if err != nil { + slog.Error(err.Error()) + return + } + + // 查询集群信息 + cluster_cmd := "kubectl cluster-info|head -1" + cluser_info, err := execCmdString(cluster_cmd) + if err != nil { + slog.Error("获取集群信息失败", "cmd", cluster_cmd, "error", err.Error()) + return + } + + // 判断cluster是否存在 + isCluster := false + for _, c := range cacheData.Data { + if c.Cluster == cluser_info { + isCluster = true + break + } + } + + // 过期或者集群不存在重新获取 + if cacheData.IsExpire() || !isCluster { + slog.Debug("缓存过期或者集群不存在重新获取", "ISEXPIRE", cacheData.IsExpire(), "ISCLUSTER", isCluster) + // TODO: 查询速度慢 简写无法处理 + // 要去kubectl api-resources结果中获取 + // 硬编码:实时获取kubectl api-resources结果 + cacheNew := utils.ResourceCache{ + Cluster: cluser_info, + } + + resourceList := []string{} + resource_cmd := "kubectl api-resources |sed 1d|awk '{print $1\" \"$2}'|xargs echo" + // 动态配置 + resources, err := execCmdString(resource_cmd) + if err != nil { + slog.Error("获取资源失败", "cmd", resource_cmd, "error", err.Error()) + return + } + + // 动态配置 + // 缺点:查询慢 + // 优点:实时匹配 + for _, c := range strings.Split(resources, " ") { + if c != " " && !strings.Contains(c, "v1") && !strings.Contains(c, "v2") { + resourceList = append(resourceList, strings.TrimSpace(strings.ReplaceAll(c, "\n", " "))) + if strings.HasPrefix(c, result[len(result)-1]) { + cmd = fmt.Sprintf("kubectl get %s -A", result[len(result)-1]) + isCmds = true + // break + } + } + } + + cacheNew.Resources = resourceList + + err = utils.WriteResourcesToYaml(&cacheNew) + if err != nil { + slog.Error("写入资源失败", "error", err.Error()) + return + } + } else { + // 读取缓存数据 + slog.Debug("读取缓存数据", "cluster", cluser_info, "ISEXPIRE", cacheData.IsExpire(), "ISCLUSTER", isCluster) + for _, v := range cacheData.Data { + if v.Cluster == cluser_info { + for _, vv := range v.Resources { + if strings.HasPrefix(vv, result[len(result)-1]) { + cmd = fmt.Sprintf("kubectl get %s -A", result[len(result)-1]) + isCmds = true + break + } + } + } + } } } @@ -209,7 +295,7 @@ func ParseCmd(in string) { // fmt.Printf("t_two %v %b\n", t_two, isLastWorkSpace) slog.Debug("补全命令失败", "结果集", t_two, "命令是否包含空格", isLastWorkSpace) } - fmt.Printf(strings.Join(t_two, "\n")) + fmt.Printf("%s", strings.Join(t_two, "\n")) } } } diff --git a/vendor/github.com/lflxp/smkubectl/completion/kill.go b/vendor/github.com/lflxp/smkubectl/completion/kill.go index 2addc058..b0ca34ba 100644 --- a/vendor/github.com/lflxp/smkubectl/completion/kill.go +++ b/vendor/github.com/lflxp/smkubectl/completion/kill.go @@ -2,6 +2,67 @@ package completion var kill = Completion{ Level: "kill", - IsShell: true, + IsShell: false, Shell: `ps -ef|awk '{for(i=2;i<=NF;++i) printf $i "\t";printf "\n"}'`, + Args: []string{ + "ARGS DESCRIPTION", + "-1 HUP (hang up)", + "-2 INT (interrupt)", + "-3 QUIT (quit)", + "-6 ABRT (abort)", + "-9 KILL (non-catchable, non-ignorable kill)", + "-14 ALRM (alarm clock)", + "-15 TERM (software termination signal)", + }, + Daughter: map[string]Completion{ + "-1": Completion{ + Level: "-9", + IsShell: true, + Shell: `ps -ef|awk '{for(i=2;i<=NF;++i) printf $i "\t";printf "\n"}'`, + IsCondition: true, + Condition: []string{"^kill.*"}, + }, + "-2": Completion{ + Level: "-9", + IsShell: true, + Shell: `ps -ef|awk '{for(i=2;i<=NF;++i) printf $i "\t";printf "\n"}'`, + IsCondition: true, + Condition: []string{"^kill.*"}, + }, + "-3": Completion{ + Level: "-9", + IsShell: true, + Shell: `ps -ef|awk '{for(i=2;i<=NF;++i) printf $i "\t";printf "\n"}'`, + IsCondition: true, + Condition: []string{"^kill.*"}, + }, + "-6": Completion{ + Level: "-9", + IsShell: true, + Shell: `ps -ef|awk '{for(i=2;i<=NF;++i) printf $i "\t";printf "\n"}'`, + IsCondition: true, + Condition: []string{"^kill.*"}, + }, + "-9": Completion{ + Level: "-9", + IsShell: true, + Shell: `ps -ef|awk '{for(i=2;i<=NF;++i) printf $i "\t";printf "\n"}'`, + IsCondition: true, + Condition: []string{"^kill.*"}, + }, + "-14": Completion{ + Level: "-9", + IsShell: true, + Shell: `ps -ef|awk '{for(i=2;i<=NF;++i) printf $i "\t";printf "\n"}'`, + IsCondition: true, + Condition: []string{"^kill.*"}, + }, + "-15": Completion{ + Level: "-9", + IsShell: true, + Shell: `ps -ef|awk '{for(i=2;i<=NF;++i) printf $i "\t";printf "\n"}'`, + IsCondition: true, + Condition: []string{"^kill.*"}, + }, + }, } diff --git a/vendor/github.com/lflxp/smkubectl/completion/showme.go b/vendor/github.com/lflxp/smkubectl/completion/showme.go index d844475f..ef2a17af 100644 --- a/vendor/github.com/lflxp/smkubectl/completion/showme.go +++ b/vendor/github.com/lflxp/smkubectl/completion/showme.go @@ -6,16 +6,18 @@ var showme = Completion{ "COMMAND DESCRIPTION", "api 快速本地DB CRUD API", "cmd 命令聚合工具", - "completion A brief description of your command", + "completion completion自动命令补全工具", "dashboard showme dashboard快速学习平台", + "django golang版本django的web框架", "help 显示showme帮助文档", "k8s k8s dashboard", "martix 黑客帝国字母雨特效", "music 本地在线音乐网站", + "monitor 实时性能监控工具", "playbook 批量主机任务编排脚本执行器", "proxy 代理服务器", - "scan A brief description of your command", - "smart A brief description of your command", + "scan 多线程IP+端口扫描工具", + "smart 智能命令数据补全工具,配合completion", "static 本地静态文件服务器", "tty web terminial", "watch go web热加载工具", @@ -89,6 +91,21 @@ var showme = Completion{ "-p --port string 端口范围,例如: 22,80,8080-9000 (default 1-65535)", }, }, + "monitor": Completion{ + Level: "monitor", + Cmd: []string{ + "ARGS DESCRIPTION", + "-c --cpu cpu info", + "-d --disk disk info", + "-h --help help for monitor", + "--lazy Print Info (include -t,-l,-c,-s,-com,-hit).", + "-l --load load info", + "-n --net 基础网络信息", + "-N --netdetail 详细网络信息", + "-s --swap swap info", + "-t --time 打印当前时间", + }, + }, "cmd": Completion{ Level: "cmd", Cmd: []string{ diff --git a/vendor/github.com/lflxp/smkubectl/utils/cache.go b/vendor/github.com/lflxp/smkubectl/utils/cache.go new file mode 100644 index 00000000..0464401e --- /dev/null +++ b/vendor/github.com/lflxp/smkubectl/utils/cache.go @@ -0,0 +1,121 @@ +/* +1. ~/.smkubectl.yaml文件的查询、创建、修改功能 +2. 获取缓存数据,计算缓存时间 +3. 每24小时更新一次 +4. 记录每个集群的api-resources +*/ +package utils + +import ( + "io" + "log/slog" + "os" + "time" + + "path/filepath" + + yaml "gopkg.in/yaml.v3" + "k8s.io/client-go/util/homedir" +) + +const kubectlYaml = ".kubectl-smart.yaml" + +var targetFile string + +func init() { + if home := homedir.HomeDir(); home != "" { + targetFile = filepath.Join(home, kubectlYaml) + } else { + targetFile = kubectlYaml + } +} + +type ResourceCache struct { + Cluster string `yaml:"cluster"` + Resources []string `yaml:"resources"` +} + +type ResourceYaml struct { + UpdateTime time.Time `yaml:"updatetime"` // 最近一次更新时间 + Data []ResourceCache `yaml:"data"` +} + +// 判断是否在24小时以内 +func (r *ResourceYaml) IsExpire() bool { + slog.Debug("判断缓存是否过期", "UpdateTime", r.UpdateTime.Add(24*time.Hour), "Now", time.Now(), "IsExpire", time.Now().After(r.UpdateTime.Add(24*time.Hour))) + if len(r.Data) == 0 { + return true + } + return time.Now().After(r.UpdateTime.Add(24 * time.Hour)) +} + +// Yaml文件转ResourceYaml +// 不存在则创建 +func ReadYamlToStruct() (*ResourceYaml, error) { + var result ResourceYaml + slog.Debug("打开缓存配置文件", "File", targetFile, "操作", "READ") + file, err := os.OpenFile(targetFile, os.O_APPEND|os.O_CREATE|os.O_RDONLY, 0644) + if err != nil { + return &result, err + } + defer file.Close() + + bytes, err := io.ReadAll(file) + if err != nil { + return &result, err + } + + if len(bytes) == 0 { + result = ResourceYaml{ + UpdateTime: time.Now(), + Data: []ResourceCache{}, + } + return &result, nil + } + + err = yaml.Unmarshal(bytes, &result) + return &result, err +} + +// ResourceYaml转Yaml +// 1. 获取本地文件 +// 2. 判断本地文件中是否含有这个集群数据 +// 3. 有则更新 没有就新增 +func WriteResourcesToYaml(data *ResourceCache) error { + list, err := ReadYamlToStruct() + if err != nil { + return err + } + + isExist := false + for index, info := range list.Data { + if info.Cluster == data.Cluster { + isExist = true + // 更新时间 + list.UpdateTime = time.Now() + list.Data[index] = *data + } + } + + if !isExist { + list.Data = append(list.Data, *data) + } + + yml, err := yaml.Marshal(list) + if err != nil { + return err + } + + return writeFile(yml) +} + +func writeFile(data []byte) error { + slog.Debug("打开缓存配置文件", "File", targetFile, "操作", "Write") + file, err := os.OpenFile(targetFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer file.Close() + + return os.WriteFile(targetFile, data, 0644) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4b4eeeaf..3b8417d4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -609,10 +609,11 @@ github.com/lflxp/lflxp-static/pkg/sync # github.com/lflxp/lflxp-tty v1.0.1 ## explicit; go 1.21.6 github.com/lflxp/lflxp-tty/pkg -# github.com/lflxp/smkubectl v0.1.3 +# github.com/lflxp/smkubectl v0.1.6 ## explicit; go 1.21.6 github.com/lflxp/smkubectl/cmd github.com/lflxp/smkubectl/completion +github.com/lflxp/smkubectl/utils # github.com/lflxp/tools v0.0.11 ## explicit; go 1.21.6 github.com/lflxp/tools/httpclient @@ -1132,7 +1133,7 @@ gopkg.in/yaml.v3 # howett.net/plist v1.0.0 ## explicit; go 1.12 howett.net/plist -# k8s.io/api v0.29.0 +# k8s.io/api v0.29.1 ## explicit; go 1.21 k8s.io/api/admissionregistration/v1 k8s.io/api/admissionregistration/v1alpha1 @@ -1186,7 +1187,7 @@ k8s.io/api/scheduling/v1beta1 k8s.io/api/storage/v1 k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1beta1 -# k8s.io/apimachinery v0.29.0 +# k8s.io/apimachinery v0.29.1 ## explicit; go 1.21 k8s.io/apimachinery/pkg/api/equality k8s.io/apimachinery/pkg/api/errors @@ -1234,7 +1235,7 @@ k8s.io/apimachinery/pkg/version k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/third_party/forked/golang/netutil k8s.io/apimachinery/third_party/forked/golang/reflect -# k8s.io/client-go v0.29.0 +# k8s.io/client-go v0.29.1 ## explicit; go 1.21 k8s.io/client-go/applyconfigurations/admissionregistration/v1 k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1