[lxc-devel] [lxd/master] Show download progress for `lxc file` and `lxc import` subcommands
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Mon Aug 6 11:32:44 UTC 2018
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 314 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180806/cfc3b8dd/attachment.bin>
-------------- next part --------------
From 5a89687c9a2f89a5ea08335e94f6f6068f4d6713 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Thu, 2 Aug 2018 19:59:18 +0200
Subject: [PATCH 1/2] lxc/file: Show progress
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxc/file.go | 116 ++++++++++++++++++++++++++++++++++++++++++++++---
shared/util.go | 17 ++++++++
2 files changed, 126 insertions(+), 7 deletions(-)
diff --git a/lxc/file.go b/lxc/file.go
index a237f50686..b82a9b9f87 100644
--- a/lxc/file.go
+++ b/lxc/file.go
@@ -15,9 +15,11 @@ import (
"github.com/spf13/cobra"
"github.com/lxc/lxd/client"
+ "github.com/lxc/lxd/lxc/utils"
"github.com/lxc/lxd/shared"
cli "github.com/lxc/lxd/shared/cmd"
"github.com/lxc/lxd/shared/i18n"
+ "github.com/lxc/lxd/shared/ioprogress"
"github.com/lxc/lxd/shared/logger"
"github.com/lxc/lxd/shared/termios"
)
@@ -328,10 +330,28 @@ func (c *cmdFilePull) Run(cmd *cobra.Command, args []string) error {
}
}
- _, err = io.Copy(f, buf)
+ progress := utils.ProgressRenderer{
+ Format: i18n.G(fmt.Sprintf("Pulling %s from %s: %%s", targetPath, pathSpec[1])),
+ }
+
+ writer := &ioprogress.ProgressWriter{
+ WriteCloser: f,
+ Tracker: &ioprogress.ProgressTracker{
+ Handler: func(bytesReceived int64, speed int64) {
+ progress.UpdateProgress(ioprogress.ProgressData{
+ Text: fmt.Sprintf("%s (%s/s)",
+ shared.GetByteSizeString(bytesReceived, 2),
+ shared.GetByteSizeString(speed, 2))})
+ },
+ },
+ }
+
+ _, err = io.Copy(writer, buf)
if err != nil {
+ progress.Done("")
return err
}
+ progress.Done("")
}
return nil
@@ -523,10 +543,9 @@ func (c *cmdFilePush) Run(cmd *cobra.Command, args []string) error {
// Transfer the files
args := lxd.ContainerFileArgs{
- Content: f,
- UID: -1,
- GID: -1,
- Mode: -1,
+ UID: -1,
+ GID: -1,
+ Mode: -1,
}
if !c.noModeChange {
@@ -560,11 +579,34 @@ func (c *cmdFilePush) Run(cmd *cobra.Command, args []string) error {
}
args.Type = "file"
+ fstat, err := f.Stat()
+ if err != nil {
+ return err
+ }
+
+ progress := utils.ProgressRenderer{
+ Format: i18n.G(fmt.Sprintf("Pushing %s to %s: %%s", f.Name(), fpath)),
+ }
+
+ args.Content = shared.NewReadSeeker(&ioprogress.ProgressReader{
+ ReadCloser: f,
+ Tracker: &ioprogress.ProgressTracker{
+ Length: fstat.Size(),
+ Handler: func(percent int64, speed int64) {
+ progress.UpdateProgress(ioprogress.ProgressData{
+ Text: fmt.Sprintf("%d%% (%s/s)", percent, shared.GetByteSizeString(speed, 2)),
+ })
+ },
+ },
+ }, f)
+
logger.Infof("Pushing %s to %s (%s)", f.Name(), fpath, args.Type)
err = resource.server.CreateContainerFile(resource.name, fpath, args)
if err != nil {
return err
+ progress.Done("")
}
+ progress.Done("")
}
return nil
@@ -605,10 +647,28 @@ func (c *cmdFile) recursivePullFile(d lxd.ContainerServer, container string, p s
return err
}
- _, err = io.Copy(f, buf)
+ progress := utils.ProgressRenderer{
+ Format: i18n.G(fmt.Sprintf("Pulling %s from %s: %%s", p, target)),
+ }
+
+ writer := &ioprogress.ProgressWriter{
+ WriteCloser: f,
+ Tracker: &ioprogress.ProgressTracker{
+ Handler: func(bytesReceived int64, speed int64) {
+ progress.UpdateProgress(ioprogress.ProgressData{
+ Text: fmt.Sprintf("%s (%s/s)",
+ shared.GetByteSizeString(bytesReceived, 2),
+ shared.GetByteSizeString(speed, 2))})
+ },
+ },
+ }
+
+ _, err = io.Copy(writer, buf)
if err != nil {
+ progress.Done("")
return err
}
+ progress.Done("")
} else if resp.Type == "symlink" {
linkTarget, err := ioutil.ReadAll(buf)
if err != nil {
@@ -650,6 +710,8 @@ func (c *cmdFile) recursivePushFile(d lxd.ContainerServer, container string, sou
Mode: int(mode.Perm()),
}
+ var readCloser io.ReadCloser
+
if fInfo.IsDir() {
// Directory handling
args.Type = "directory"
@@ -662,6 +724,7 @@ func (c *cmdFile) recursivePushFile(d lxd.ContainerServer, container string, sou
args.Type = "symlink"
args.Content = bytes.NewReader([]byte(symlinkTarget))
+ readCloser = ioutil.NopCloser(args.Content)
} else {
// File handling
f, err := os.Open(p)
@@ -672,10 +735,49 @@ func (c *cmdFile) recursivePushFile(d lxd.ContainerServer, container string, sou
args.Type = "file"
args.Content = f
+ readCloser = f
+ }
+
+ progress := utils.ProgressRenderer{
+ Format: i18n.G(fmt.Sprintf("Pushing %s to %s: %%s", p, targetPath)),
+ }
+
+ if args.Type != "directory" {
+ contentLength, err := args.Content.Seek(0, io.SeekEnd)
+ if err != nil {
+ return err
+ }
+
+ _, err = args.Content.Seek(0, io.SeekStart)
+ if err != nil {
+ return err
+ }
+
+ args.Content = shared.NewReadSeeker(&ioprogress.ProgressReader{
+ ReadCloser: readCloser,
+ Tracker: &ioprogress.ProgressTracker{
+ Length: contentLength,
+ Handler: func(percent int64, speed int64) {
+ progress.UpdateProgress(ioprogress.ProgressData{
+ Text: fmt.Sprintf("%d%% (%s/s)", percent,
+ shared.GetByteSizeString(speed, 2))})
+ },
+ },
+ }, args.Content)
}
logger.Infof("Pushing %s to %s (%s)", p, targetPath, args.Type)
- return d.CreateContainerFile(container, targetPath, args)
+ err = d.CreateContainerFile(container, targetPath, args)
+ if err != nil {
+ if args.Type != "directory" {
+ progress.Done("")
+ }
+ return err
+ }
+ if args.Type != "directory" {
+ progress.Done("")
+ }
+ return nil
}
return filepath.Walk(source, sendFile)
diff --git a/shared/util.go b/shared/util.go
index c098b0d50f..85706702f5 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -1087,3 +1087,20 @@ func ParseNumberFromFile(file string) (int64, error) {
return int64(nr), nil
}
+
+type ReadSeeker struct {
+ io.Reader
+ io.Seeker
+}
+
+func NewReadSeeker(reader io.Reader, seeker io.Seeker) *ReadSeeker {
+ return &ReadSeeker{Reader: reader, Seeker: seeker}
+}
+
+func (r *ReadSeeker) Read(p []byte) (n int, err error) {
+ return r.Reader.Read(p)
+}
+
+func (r *ReadSeeker) Seek(offset int64, whence int) (int64, error) {
+ return r.Seeker.Seek(offset, whence)
+}
From 4bbe6f566506727b5d8bccd2384e9f6346a8d757 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Fri, 3 Aug 2018 10:29:52 +0200
Subject: [PATCH 2/2] lxc/import: Show progress
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxc/import.go | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/lxc/import.go b/lxc/import.go
index b532a6a7d1..0138a35603 100644
--- a/lxc/import.go
+++ b/lxc/import.go
@@ -1,14 +1,17 @@
package main
import (
+ "fmt"
"os"
"github.com/spf13/cobra"
"github.com/lxc/lxd/client"
+ "github.com/lxc/lxd/lxc/utils"
"github.com/lxc/lxd/shared"
cli "github.com/lxc/lxd/shared/cmd"
"github.com/lxc/lxd/shared/i18n"
+ "github.com/lxc/lxd/shared/ioprogress"
)
type cmdImport struct {
@@ -56,13 +59,35 @@ func (c *cmdImport) Run(cmd *cobra.Command, args []string) error {
}
defer file.Close()
+ fstat, err := file.Stat()
+ if err != nil {
+ return err
+ }
+
+ progress := utils.ProgressRenderer{Format: i18n.G("Importing container: %s")}
+
createArgs := lxd.ContainerBackupArgs{}
- createArgs.BackupFile = file
+ createArgs.BackupFile = &ioprogress.ProgressReader{
+ ReadCloser: file,
+ Tracker: &ioprogress.ProgressTracker{
+ Length: fstat.Size(),
+ Handler: func(percent int64, speed int64) {
+ progress.UpdateProgress(ioprogress.ProgressData{Text: fmt.Sprintf("%d%% (%s/s)", percent, shared.GetByteSizeString(speed, 2))})
+ },
+ },
+ }
op, err := resource.server.CreateContainerFromBackup(createArgs)
if err != nil {
return err
}
- return op.Wait()
+ err = op.Wait()
+ if err != nil {
+ progress.Done("")
+ return err
+ }
+ progress.Done("")
+
+ return nil
}
More information about the lxc-devel
mailing list