0

When pulling an image with ImagePull(), there is extensive stdout in the terminal showing the progress of the Pull, i.e.;

{"status":"Downloading","progressDetail":{"current":6433248,"total":7964517},"progress":"[========================================\u003e          ]  6.433MB/7.965MB","id":"ae5cee1a3f12"}
func PullImage(imageName string) bool {
    ctx := context.Background()
    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
    if err != nil {
        log.Error(err)
        return false
    }

    //TODO: Need to disable Stdout!!
    log.Info("\t\tPulling image " + imageName)
    out, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{})
    if err != nil {
        log.Error(err)
        return false
    }
    defer out.Close()

    io.Copy(os.Stdout, out)

    log.Info("Pulled image " + imageName + " into host")

    return true
}

I have searched the documentation and haven't found a way to disable StdOut or change verbosity.

I don't really understand the io.Copy(os.Stdout, out) line, but disabling it causes no image to be pulled, as far as I can tell.

How can we hide the output from ImagePull()?

Marcus Jones
  • 960
  • 3
  • 11
  • 27
  • I don't see any output when running [this](https://pastebin.pl/view/00fe482a) – Omer Tuchfeld Oct 24 '20 at 21:40
  • I tried with `_, err = cli.ImagePull(ctx, os.Args[1], types.ImagePullOptions{})`, but the image is not pulled into my machine. – Marcus Jones Oct 26 '20 at 14:32
  • What do you mean? Did you remember to pass the image name as commandline arguments to my script? I'm not telling you how to solve your problem, I'm just showing you an example script that is practically identical to yours where that problem doesn't occur, as a way to show you that the problem that you describe doesn't reproduce. – Omer Tuchfeld Oct 26 '20 at 15:02
  • Thanks, the script helps, but still confused. I see the image does get pulled with `docker image ls`, but *only* after CTRL-C on your script with the infinite loop. I think what I'm after is a way to handle the returned [ReadCloser](https://godoc.org/io#ReadCloser) object which is new for me. – Marcus Jones Oct 26 '20 at 19:49
  • This [question](https://stackoverflow.com/questions/44452679/golang-docker-api-parse-result-of-imagepull) gets really close to what I was looking for - block the process until image is pulled, and finally print status done. – Marcus Jones Oct 26 '20 at 20:22

1 Answers1

2

I don't really understand the io.Copy(os.Stdout, out) line, but disabling it causes no image to be pulled, as far as I can tell.

io.Copy simply reads all data from an io.Reader (in this case an io.ReadCloser which is also an io.Reader) and writes it into an io.Writer.

My understanding is that if you don't perform this step, main returns before ImagePull gets a chance to finish in the background.

However, if you do perform io.Copy, the copying keeps main busy long enough for the pull to actually finish.

In my example in the comments above, I kept main busy with a for / sleep loop instead.

The reason you see all the output is because... well, you copy the output of ImagePull to Stdout with io.Copy(os.Stdout, out), so it's no surprise we see the output of ImagePull in stdout.

If instead we copied all output into some "blackhole" that makes the output disappear, we'd keep main busy while the copy is happening while suppressing all of its output.

One way to do that is to use io/ioutil's ioutil.Discard. This is an io.Writer that simply throws away all data written to it.

So simply replace you io.Copy(os.Stdout, out) line with the following:

import {
    "io/ioutil"
}

io.Copy(ioutil.Discard, out)
Omer Tuchfeld
  • 2,886
  • 1
  • 17
  • 24
  • Tested and works, thanks! I implemented event handling and logging as well according to [this thread](https://stackoverflow.com/questions/44452679/golang-docker-api-parse-result-of-imagepull) – Marcus Jones Nov 14 '20 at 07:17