diff --git a/internal/kubectl/pod_file.go b/internal/kubectl/pod_file.go index ff2d74f..f336fb1 100644 --- a/internal/kubectl/pod_file.go +++ b/internal/kubectl/pod_file.go @@ -24,15 +24,15 @@ type PodFileNode struct { IsDir bool `json:"isDir"` // 指示是否 } -// PodFile 应用配置结构 -type PodFile struct { +// PodFileInfo 应用配置结构 +type PodFileInfo struct { Namespace string PodName string ContainerName string } // GetFileList 获取容器中指定路径的文件和目录列表 -func (p *PodFile) GetFileList(path string) ([]*PodFileNode, error) { +func (p *PodFileInfo) GetFileList(path string) ([]*PodFileNode, error) { cmd := []string{"ls", "-l", path} req := kubectl.client.CoreV1().RESTClient(). Get(). @@ -67,49 +67,8 @@ func (p *PodFile) GetFileList(path string) ([]*PodFileNode, error) { return p.parseFileList(path, stdout.String()), nil } -// parseFileList 解析输出并生成 PodFileNode 列表 -func (p *PodFile) 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 -} - // DownloadFile 从指定容器下载文件 -func (p *PodFile) DownloadFile(filePath string) ([]byte, error) { +func (p *PodFileInfo) DownloadFile(filePath string) ([]byte, error) { cmd := []string{"cat", filePath} klog.V(8).Infof("DownloadFile %s", filePath) @@ -151,13 +110,18 @@ func (p *PodFile) DownloadFile(filePath string) ([]byte, error) { } // UploadFile 将文件上传到指定容器 -func (p *PodFile) UploadFile(destPath string, file multipart.File) error { +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 os.Remove(tempFile.Name()) // 确保临时文件在函数结束时被删除 + 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) @@ -197,7 +161,12 @@ func (p *PodFile) UploadFile(destPath string, file multipart.File) error { if err != nil { return fmt.Errorf("error opening file: %v", err) } - defer readFile.Close() + 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, @@ -212,14 +181,19 @@ func (p *PodFile) UploadFile(destPath string, file multipart.File) error { return nil } -func (p *PodFile) SaveFile(path string, context string) error { +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 os.Remove(tempFile.Name()) // 确保临时文件在函数结束时被删除 + 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) @@ -259,7 +233,12 @@ func (p *PodFile) SaveFile(path string, context string) error { if err != nil { return fmt.Errorf("error opening file: %v", err) } - defer file.Close() + 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, @@ -309,3 +288,44 @@ func getFileType(permissions string) string { 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/main.go b/main.go index 3392f8b..7e19502 100644 --- a/main.go +++ b/main.go @@ -111,14 +111,11 @@ func main() { api.GET("/chat/sse", chat.Sse) // pod 文件浏览上传下载 - api.POST("/file/list", pod.FileListHandler) - api.POST("/file/show", pod.ShowFileHandler) - api.POST("/file/save", pod.SaveFileHandler) - api.POST("/file/download", pod.DownloadFileHandler) - api.POST("/file/upload", pod.UploadFileHandler) - - // k8s pod - // http://127.0.0.1:3618/k8s/doc/gvk/stable.example.com%2Fv1/CronTab + api.POST("/file/list", pod.FileList) + api.POST("/file/show", pod.ShowFile) + api.POST("/file/save", pod.SaveFile) + api.POST("/file/download", pod.DownloadFile) + api.POST("/file/upload", pod.UploadFile) } diff --git a/pkg/controller/pod/pod_file.go b/pkg/controller/pod/pod_file.go index e148613..10d10cc 100644 --- a/pkg/controller/pod/pod_file.go +++ b/pkg/controller/pod/pod_file.go @@ -24,8 +24,8 @@ type info struct { FileType string `json:"type,omitempty"` // 只有file类型可以查、下载 } -// FileListHandler 处理获取文件列表的 HTTP 请求 -func FileListHandler(c *gin.Context) { +// FileList 处理获取文件列表的 HTTP 请求 +func FileList(c *gin.Context) { info := &info{} err := c.ShouldBindBodyWithJSON(info) if err != nil { @@ -33,7 +33,7 @@ func FileListHandler(c *gin.Context) { return } - pf := kubectl.PodFile{ + pf := kubectl.PodFileInfo{ Namespace: info.Namespace, PodName: info.PodName, ContainerName: info.ContainerName, @@ -51,8 +51,8 @@ func FileListHandler(c *gin.Context) { amis.WriteJsonList(c, nodes) } -// ShowFileHandler 处理下载文件的 HTTP 请求 -func ShowFileHandler(c *gin.Context) { +// ShowFile 处理下载文件的 HTTP 请求 +func ShowFile(c *gin.Context) { info := &info{} err := c.ShouldBindBodyWithJSON(info) if err != nil { @@ -60,7 +60,7 @@ func ShowFileHandler(c *gin.Context) { return } - pf := kubectl.PodFile{ + pf := kubectl.PodFileInfo{ Namespace: info.Namespace, PodName: info.PodName, ContainerName: info.ContainerName, @@ -78,11 +78,6 @@ func ShowFileHandler(c *gin.Context) { return } - // if info.Size > 1024*10 { - // // 大于10KB - // amis.WriteJsonError(c, fmt.Errorf("文件较大,请下载后查看")) - // return - // } // 从容器中下载文件 fileContent, err := pf.DownloadFile(info.Path) if err != nil { @@ -103,7 +98,7 @@ func ShowFileHandler(c *gin.Context) { "content": fileContent, }) } -func SaveFileHandler(c *gin.Context) { +func SaveFile(c *gin.Context) { info := &info{} err := c.ShouldBindBodyWithJSON(info) if err != nil { @@ -111,7 +106,7 @@ func SaveFileHandler(c *gin.Context) { return } - pf := kubectl.PodFile{ + pf := kubectl.PodFileInfo{ Namespace: info.Namespace, PodName: info.PodName, ContainerName: info.ContainerName, @@ -141,8 +136,8 @@ func SaveFileHandler(c *gin.Context) { amis.WriteJsonOK(c) } -// DownloadFileHandler 处理下载文件的 HTTP 请求 -func DownloadFileHandler(c *gin.Context) { +// DownloadFile 处理下载文件的 HTTP 请求 +func DownloadFile(c *gin.Context) { info := &info{} err := c.ShouldBindBodyWithJSON(info) if err != nil { @@ -150,7 +145,7 @@ func DownloadFileHandler(c *gin.Context) { return } - pf := kubectl.PodFile{ + pf := kubectl.PodFileInfo{ Namespace: info.Namespace, PodName: info.PodName, ContainerName: info.ContainerName, @@ -168,8 +163,8 @@ func DownloadFileHandler(c *gin.Context) { c.Data(http.StatusOK, "application/octet-stream", fileContent) } -// UploadFileHandler 处理上传文件的 HTTP 请求 -func UploadFileHandler(c *gin.Context) { +// UploadFile 处理上传文件的 HTTP 请求 +func UploadFile(c *gin.Context) { info := &info{} info.ContainerName = c.PostForm("containerName") @@ -188,7 +183,7 @@ func UploadFileHandler(c *gin.Context) { } // 删除path最后一个/后面的内容,取当前选中文件的父级路径 - pf := kubectl.PodFile{ + pf := kubectl.PodFileInfo{ Namespace: info.Namespace, PodName: info.PodName, ContainerName: info.ContainerName,