diff --git a/internal/api/v1/file/file.go b/internal/api/v1/file/file.go index 0a4b6396..25f9f4f9 100644 --- a/internal/api/v1/file/file.go +++ b/internal/api/v1/file/file.go @@ -152,6 +152,32 @@ func (h *Handler) RmFolder() iris.Handler { } } +func (h *Handler) DownloadFolder() iris.Handler { + return func(ctx *context.Context) { + + var req fileModel.Request + req.Path = ctx.URLParam("path") + req.Namespace = ctx.URLParam("namespace") + req.Cluster = ctx.URLParam("cluster") + req.PodName = ctx.URLParam("podName") + req.ContainerName = ctx.URLParam("containerName") + + file, err := h.fileService.DownloadFolder(req) + if err != nil { + ctx.StatusCode(iris.StatusInternalServerError) + ctx.Values().Set("message", err.Error()) + return + } + filename := path.Base(file) + err = ctx.SendFile(file, filename) + if err != nil { + ctx.StatusCode(iris.StatusInternalServerError) + ctx.Values().Set("message", err.Error()) + return + } + os.RemoveAll(file) + } +} func (h *Handler) DownloadFile() iris.Handler { return func(ctx *context.Context) { @@ -257,5 +283,6 @@ func Install(parent iris.Party) { sp.Post("/files/rename", handler.ReNameFile()) sp.Post("/files/upload", handler.UploadFile()) sp.Post("/files/update", handler.UpdateFile()) - sp.Get("/files/download", handler.DownloadFile()) + sp.Get("/files/download/folder", handler.DownloadFolder()) + sp.Get("/files/download/file", handler.DownloadFile()) } diff --git a/internal/service/v1/file/file.go b/internal/service/v1/file/file.go index ccb5639a..0de9ed57 100644 --- a/internal/service/v1/file/file.go +++ b/internal/service/v1/file/file.go @@ -20,6 +20,7 @@ import ( type Service interface { ListFiles(request file.Request) ([]podtool.File, error) DownloadFile(request file.Request) (string, error) + DownloadFolder(request file.Request) (string, error) UploadFile(request file.Request) error ExecNewCommand(request file.Request) ([]byte, error) EditFile(request file.Request) error @@ -90,6 +91,27 @@ func (f service) EditFile(request file.Request) error { func (f service) DownloadFile(request file.Request) (string, error) { + var fileP string + pt, err := f.GetPodTool(request) + if err != nil { + return fileP, err + } + fileNameWithSuffix := path.Base(request.Path) + fileP = filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().UnixNano())) + err = os.MkdirAll(fileP, os.ModePerm) + if err != nil { + return "", err + } + fileP = filepath.Join(fileP, fileNameWithSuffix) + err = pt.CopyFileFromPod(request.Path, fileP) + if err != nil { + return "", err + } + + return fileP, nil +} +func (f service) DownloadFolder(request file.Request) (string, error) { + var fileP string pt, err := f.GetPodTool(request) if err != nil { @@ -104,7 +126,7 @@ func (f service) DownloadFile(request file.Request) (string, error) { return "", err } fileP = filepath.Join(fileP, fileName+".tar") - err = pt.CopyFromPod(request.Path, fileP) + err = pt.CopyFolderFromPod(request.Path, fileP) if err != nil { return "", err } diff --git a/pkg/util/podtool/copyfrompod.go b/pkg/util/podtool/copyfrompod.go index 86b76f75..386d783a 100644 --- a/pkg/util/podtool/copyfrompod.go +++ b/pkg/util/podtool/copyfrompod.go @@ -5,8 +5,54 @@ import ( "io" "os" ) +func (p *PodTool) CopyFileFromPod(filePath string, destPath string) error { + reader, outStream := io.Pipe() -func (p *PodTool) CopyFromPod(filePath string, destPath string) error { + p.ExecConfig = ExecConfig{ + Command: []string{"cat", filePath}, + Stdin: os.Stdin, + Stdout: outStream, + Stderr: os.Stderr, + NoPreserve: true, + } + + err := p.Exec(Download) + if err != nil { + return err + } + + file, err := os.OpenFile(destPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + return err + } + + r := bufio.NewReader(reader) + w := bufio.NewWriter(file) + size := 4 * 1024 + buf := make([]byte, 4*1024) + for { + n, err := r.Read(buf) + if err != nil && err != io.EOF { + return err + } + if n == 0 { + break + } + _, err = w.Write(buf[:n]) + if err != nil { + return err + } + if n < size { + break + } + } + err = w.Flush() + if err != nil { + return err + } + return err +} +func (p *PodTool) CopyFolderFromPod(filePath string, destPath string) error { reader, outStream := io.Pipe() p.ExecConfig = ExecConfig{ diff --git a/web/dashboard/src/business/workloads/pods/podfilebrowser/index.vue b/web/dashboard/src/business/workloads/pods/podfilebrowser/index.vue index d54ca9ff..c540e0d5 100644 --- a/web/dashboard/src/business/workloads/pods/podfilebrowser/index.vue +++ b/web/dashboard/src/business/workloads/pods/podfilebrowser/index.vue @@ -420,7 +420,11 @@ export default { return } const url = this.getUrl(row.name) - window.open("/kubepi/api/v1/pod/files/download" + url, "_blank") + //区分文件和目录,目录tar打包下载,文件直接下载(应对部分镜像tar命令异常导致下载不了) + if(row["mode"].startsWith("d")) + window.open("/kubepi/api/v1/pod/files/download/folder" + url, "_blank") + else + window.open("/kubepi/api/v1/pod/files/download/file" + url, "_blank") }, getUrl (name) { this.fileRequest.path = this.getPath(name) diff --git a/web/dashboard/src/components/detail/detail-containers.vue b/web/dashboard/src/components/detail/detail-containers.vue index 12bc82e1..a0035e6a 100644 --- a/web/dashboard/src/components/detail/detail-containers.vue +++ b/web/dashboard/src/components/detail/detail-containers.vue @@ -127,6 +127,16 @@ export default { return !checkPermissions({ scope: "namespace", apiGroup: "", resource: "pods/exec", verb: "create" }) }, }, + { + label: this.$t("business.pod.pod_file"), + icon: "el-icon-files", + click: (row) => { + this.openPodFiles(row) + }, + disabled: () => { + return !checkPermissions({ scope: "namespace", apiGroup: "", resource: "pods/exec", verb: "create" }) + }, + }, ], form: {}, namespace: "", @@ -151,6 +161,11 @@ export default { let routeUrl = this.$router.resolve({ path: "/terminal", query: { cluster: this.cluster, namespace: this.namespace, pod: this.name, container: row.container.name, type: "log" } }) window.open(routeUrl.href, "_blank") }, + openPodFiles(row) { + this.$router.push({ name: "PodFile", params: { namespace: this.yamlInfo.metadata.namespace, name: this.yamlInfo.metadata.name },query:{ + container: row.container.name + }}) + }, }, }