Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional progress info when pulling images via libpod endpoint #14886

Closed
wants to merge 1 commit into from

Conversation

jmguzik
Copy link
Contributor

@jmguzik jmguzik commented Jul 11, 2022

/fixes #12341

$ curl -XPOST --unix-socket /run/user/${UID}/podman/podman.sock   -H content-type:application/json   "http://d/v4.0.0/libpod/images/pull?reference=docker.io%2Flibrary%2Fmysql&progress=true"
{"stream":"Trying to pull docker.io/library/mysql:latest...\n"}
{"stream":"Getting image source signatures\n"}
{"stream":"Copying blob sha256:87f3aa8373015766399afc3280b7482559b01b7e66cf7a908895b763411030ac\n"}
{"stream":"Copying blob sha256:87f3aa8373015766399afc3280b7482559b01b7e66cf7a908895b763411030ac\n"}
{"stream":"Copying blob sha256:bb429e544310419a3cd729479c47eb7b834676be1ac091dff00e8087402d8c97\n"}
{"stream":"Copying blob sha256:bb429e544310419a3cd729479c47eb7b834676be1ac091dff00e8087402d8c97\n"}
{"stream":"Copying blob sha256:a1dd213a3236752eb500bedc1296fcd8b9485906292cb9a358cba5c0c38ded31\n"}
{"stream":"Copying blob sha256:a1dd213a3236752eb500bedc1296fcd8b9485906292cb9a358cba5c0c38ded31\n"}
{"stream":"Copying blob sha256:e54b73e95ef388354463a761e4e93ce3dac29cb244b2dc0424f2f4afc6ddf5cd\n"}
{"stream":"Copying blob sha256:e54b73e95ef388354463a761e4e93ce3dac29cb244b2dc0424f2f4afc6ddf5cd\n"}
{"stream":"Copying blob sha256:c148b3f9047c21af681257a3301bc925e1a63a6071ca04137df7e8e5ac15e778\n"}
{"stream":"Copying blob sha256:c148b3f9047c21af681257a3301bc925e1a63a6071ca04137df7e8e5ac15e778\n"}
{"stream":"Copying blob sha256:297095d1476d409ad25b3ba8fe91e2d57ef51d3b241935180ac85517c1502ae1\n"}
{"stream":"Copying blob sha256:297095d1476d409ad25b3ba8fe91e2d57ef51d3b241935180ac85517c1502ae1\n"}
{"status":"Pulling fs layer","id":"a1dd213a3236"}
{"status":"Pulling fs layer","id":"e54b73e95ef3"}
{"status":"Pulling fs layer","id":"87f3aa837301"}
{"status":"Pulling fs layer","id":"c148b3f9047c"}
{"status":"Pulling fs layer","id":"297095d1476d"}
{"status":"Download complete","id":"87f3aa837301"}
{"status":"Pulling fs layer","id":"bb429e544310"}
{"status":"Download complete","id":"297095d1476d"}
{"stream":"Copying blob sha256:5350194364819a9e2eed735d032609aaf9fe69b6d270e0a6cc41469a57af840e\n"}
{"stream":"Copying blob sha256:5350194364819a9e2eed735d032609aaf9fe69b6d270e0a6cc41469a57af840e\n"}
{"status":"Download complete","id":"bb429e544310"}
{"stream":"Copying blob sha256:23722cff1cc365fa44e2d131fab041780a96ae21fac7d377f5bd228c8b3261f9\n"}
{"stream":"Copying blob sha256:23722cff1cc365fa44e2d131fab041780a96ae21fac7d377f5bd228c8b3261f9\n"}
{"stream":"Copying blob sha256:eb19883dc4c6df1517140f07ec2cdebddb0a1337388ffd6f0926616c86021f3e\n"}
{"stream":"Copying blob sha256:eb19883dc4c6df1517140f07ec2cdebddb0a1337388ffd6f0926616c86021f3e\n"}
{"status":"Download complete","id":"c148b3f9047c"}
{"stream":"Copying blob sha256:6eaa2c23609563b5d81f97470ce85037d66b4fcc9fbdb10dab332c0d8b1bce40\n"}
{"stream":"Copying blob sha256:6eaa2c23609563b5d81f97470ce85037d66b4fcc9fbdb10dab332c0d8b1bce40\n"}
{"status":"Download complete","id":"a1dd213a3236"}
{"status":"Pulling fs layer","id":"23722cff1cc3"}
{"status":"Download complete","id":"23722cff1cc3"}
{"status":"Downloading","progressDetail":{"current":16267647,"total":39222121},"progress":"[====================\u003e                              ]  16.27MB/39.22MB","id":"e54b73e95ef3"}
{"status":"Pulling fs layer","id":"eb19883dc4c6"}
{"status":"Pulling fs layer","id":"6eaa2c236095"}
{"status":"Download complete","id":"6eaa2c236095"}
{"status":"Downloading","progressDetail":{"current":33163647,"total":39222121},"progress":"[==========================================\u003e        ]  33.16MB/39.22MB","id":"e54b73e95ef3"}
{"status":"Downloading","progressDetail":{"current":9197951,"total":39781531},"progress":"[===========\u003e                                       ]  9.198MB/39.78MB","id":"eb19883dc4c6"}
{"status":"Pulling fs layer","id":"535019436481"}
{"status":"Downloading","progressDetail":{"current":24000895,"total":39781531},"progress":"[==============================\u003e                    ]     24MB/39.78MB","id":"eb19883dc4c6"}
{"status":"Downloading","progressDetail":{"current":3209599,"total":47260578},"progress":"[===\u003e                                               ]   3.21MB/47.26MB","id":"535019436481"}
{"status":"Download complete","id":"e54b73e95ef3"}
{"status":"Downloading","progressDetail":{"current":38693247,"total":39781531},"progress":"[================================================\u003e  ]  38.69MB/39.78MB","id":"eb19883dc4c6"}
{"status":"Downloading","progressDetail":{"current":8530303,"total":47260578},"progress":"[=========\u003e                                         ]   8.53MB/47.26MB","id":"535019436481"}
{"status":"Download complete","id":"eb19883dc4c6"}
{"status":"Downloading","progressDetail":{"current":22497663,"total":47260578},"progress":"[=======================\u003e                           ]   22.5MB/47.26MB","id":"535019436481"}
{"status":"Downloading","progressDetail":{"current":40151423,"total":47260578},"progress":"[==========================================\u003e        ]  40.15MB/47.26MB","id":"535019436481"}
{"status":"Download complete","id":"535019436481"}
{"stream":"Copying config sha256:7e7e458be53cabe4d12b9d6d18511445d79ee96ef00441a23a6d1eab279d99a5\n"}
{"status":"Pulling fs layer","id":"7e7e458be53c"}
{"status":"Download complete","id":"7e7e458be53c"}
{"stream":"Writing manifest to image destination\n"}
{"stream":"Storing signatures\n"}
{"images":["7e7e458be53cabe4d12b9d6d18511445d79ee96ef00441a23a6d1eab279d99a5"],"id":"7e7e458be53cabe4d12b9d6d18511445d79ee96ef00441a23a6d1eab279d99a5"}

Does this PR introduce a user-facing change?

progress parameter introduced to libpod/images/pull, the default value is false

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jul 11, 2022

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: jmguzik
To complete the pull request process, please assign ashley-cui after the PR has been reviewed.
You can assign the PR to them by writing /assign @ashley-cui in a comment when ready.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@jmguzik jmguzik force-pushed the progress branch 5 times, most recently from 3a22ea3 to 7a0a278 Compare July 11, 2022 11:03
Copy link
Member

@vrothberg vrothberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't address the issue, unfortunately. There is much more needed to get the real pull progress. In it's current form the PR just prints the same lines multiple times, see

./bin/podman-remote pull nginx
Resolved "nginx" as an alias (/home/vrothberg/.cache/containers/short-name-aliases.co
Trying to pull docker.io/library/nginx:latest...
Getting image source signatures
Copying blob sha256:fe0ef4c895f5ea450aca17342e481fada37bf2a1ee85d127a4473216c3f672ea
Copying blob sha256:fe0ef4c895f5ea450aca17342e481fada37bf2a1ee85d127a4473216c3f672ea
Copying blob sha256:f4407ba1f103abb9ae05a4b2891c7ebebaecab0c262535fc6659a628db25df44
Copying blob sha256:f4407ba1f103abb9ae05a4b2891c7ebebaecab0c262535fc6659a628db25df44
Copying blob sha256:935cecace2a02d2545e0c19bd52fe9c8c728fbab2323fc274e029f5357cda689
Copying blob sha256:935cecace2a02d2545e0c19bd52fe9c8c728fbab2323fc274e029f5357cda689
Copying blob sha256:4a7307612456a7f65365e1da5c3811df49cefa5a2fd68d8e04e093d26a395d60
Copying blob sha256:4a7307612456a7f65365e1da5c3811df49cefa5a2fd68d8e04e093d26a395d60
Copying blob sha256:8f46223e4234ce76b244c074e79940b9ee0a01b42050012c8555ebc7ac59469e
Copying blob sha256:8f46223e4234ce76b244c074e79940b9ee0a01b42050012c8555ebc7ac59469e
Copying blob sha256:b85a868b505ffd0342a37e6a3b1c49f7c71878afe569a807e6238ef08252fcb7
Copying blob sha256:b85a868b505ffd0342a37e6a3b1c49f7c71878afe569a807e6238ef08252fcb7

What needs to be done is discussed in the issue, see #12341 (comment) and other comments.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 11, 2022

Nevermind my comments, I think I know what you mean :)

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 11, 2022

@vrothberg Is that kind of output you are looking for?

$ ./podman-remote pull nginx
Resolved "nginx" as an alias (/home/jguzik/.cache/containers/short-name-aliases.conf)
Trying to pull docker.io/library/nginx:latest...
Getting image source signatures
Copying blob b85a868b505f skipped: already exists
Copying blob f4407ba1f103 pulling fs layer
Copying blob 935cecace2a0 pulling fs layer
Copying blob fe0ef4c895f5 pulling fs layer
Copying blob 935cecace2a0 done
Copying blob fe0ef4c895f5 done
Copying blob 4a7307612456 pulling fs layer
Copying blob 4a7307612456 done
Copying blob 8f46223e4234 pulling fs layer
Copying blob 8f46223e4234 done
Copying blob f4407ba1f103 [========================>                          ]  12.17MB/25.35MB
Copying blob f4407ba1f103 done
Copying config sha256:55f4b40fe486a5b734b46bb7bf28f52fa31426bf23be068c8e7b19e58d9b8deb
Copying blob 55f4b40fe486 pulling fs layer
Copying blob 55f4b40fe486 done
Writing manifest to image destination
Storing signatures
55f4b40fe486a5b734b46bb7bf28f52fa31426bf23be068c8e7b19e58d9b8deb

Progress channel emits properties anyway, so I reconstructed the message in place.

@vrothberg
Copy link
Member

vrothberg commented Jul 12, 2022

@jmguzik it does not work as you may expect it to. The progress for a given blob is printed multiple times (see your example above). As #12341 (comment) suggests, we had to do plumbing in c/image.

The progress bars for the local/native client are rendered in the containers/image library. To achieve the same progress bars on the remote client, we had to refactor the progress-bar logic, make it usable for callers outside of c/image and then do the plumbing for podman's remote API/client.

It's quite some work.

Cc: @mtrmac

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 12, 2022

@vrothberg I have no problem with some work (a matter of time only) but I have to understand it first. I have a problem with that. Do you expect curl output to be replaced in the process? Is something like this even possible after flushing?
Progress bar blob is printed multiple times in docker too, using REST API, so I wonder how this could be achieved using it. I think I have never seen a similar example with an override flushed line...

Let's forget about podman-remote because I haven't checked things there really. Let's focus how it should look like via REST.

@vrothberg
Copy link
Member

@vrothberg I have no problem with some work (a matter of time only) but I have to understand it first. I have a problem with that. Do you expect curl output to be replaced in the process? Is something like this even possible after flushing?

I pretty much shared everything I know:

  • The output of podman pull and podman-remote pull should be identical
  • Currently, podman-remote pull does render any progress bars but only indicates that a given blob is pulled
  • All progress-bar logic is in containers/image and not accessible to outside callers

Progress bar blob is printed multiple times in docker too, using REST API, so I wonder how this could be achieved using it.

I am certain Docker does not print the lines redundantly. docker pull nginx renders everything correctly/as I expect it to.

Let's forget about podman-remote because I haven't checked things there really. Let's focus how it should look like via REST.

In order to render progress bars we need to know a number of things:

  1. What is being copied (e.g., config, blob)
  2. What is the total size
  3. How much data has been copied

I think the Docker-compat endpoint does parts of that already, so it may be worth checking out what's happening there. I'd also have a look at what Docker does exactly.

Thanks a lot for looking into this, @jmguzik, I appreciate your help!

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 12, 2022

I think the Docker-compat endpoint does parts of that already, so it may be worth checking out what's happening there. I'd also have a look at what Docker does exactly.

I already did that, before jumping into the code.
An example from docker itself (snippet) REST API, bar not replaced:

{"status":"Digest: sha256:7746df395af22f04212cd25a92c1d6dbc5a06a0ca9579a229ef43008d4d1302a"}
{"status":"Pulling from library/alpine","id":"3.9.5"}
{"status":"Pulling fs layer","progressDetail":{},"id":"9123ac7c32f7"}
{"status":"Downloading","progressDetail":{"current":27993,"total":2764173},"progress":"[\u003e                                                  ]  27.99kB/2.764MB","id":"9123ac7c32f7"}
{"status":"Downloading","progressDetail":{"current":571736,"total":2764173},"progress":"[==========\u003e                                        ]  571.7kB/2.764MB","id":"9123ac7c32f7"}
{"status":"Downloading","progressDetail":{"current":1300824,"total":2764173},"progress":"[=======================\u003e                           ]  1.301MB/2.764MB","id":"9123ac7c32f7"}
{"status":"Downloading","progressDetail":{"current":1984856,"total":2764173},"progress":"[===================================\u003e               ]  1.985MB/2.764MB","id":"9123ac7c32f7"}
{"status":"Downloading","progressDetail":{"current":2764173,"total":2764173},"progress":"[==================================================\u003e]  2.764MB/2.764MB","id":"9123ac7c32f7"}
{"status":"Download complete","progressDetail":{},"id":"9123ac7c32f7"}
{"status":"Extracting","progressDetail":{"current":32768,"total":2764173},"progress":"[\u003e                                                  ]  32.77kB/2.764MB","id":"9123ac7c32f7"}
{"status":"Extracting","progressDetail":{"current":2764173,"total":2764173},"progress":"[==================================================\u003e]  2.764MB/2.764MB","id":"9123ac7c32f7"}
{"status":"Pull complete","progressDetail":{},"id":"9123ac7c32f7"}

And in the podman<->docker compat layer its more or less happening the same as what is happening in my PR (BTW I can add the same progress bar as it is in docker to compat, it's missing):

$ curl -XPOST --unix-socket /run/user/${UID}/podman/podman.sock -H content-type:application/json http://d/v4.0.0/images/create?fromImage=fedora
{"status":"Pulling fs layer","progressDetail":{},"id":"e1deda52ffad"}
{"status":"Downloading","progressDetail":{"current":26622335,"total":58926165},"id":"e1deda52ffad"}
{"status":"Downloading","progressDetail":{"current":55052671,"total":58926165},"id":"e1deda52ffad"}
{"status":"Download complete","progressDetail":{},"id":"e1deda52ffad"}
{"status":"Pulling fs layer","progressDetail":{},"id":"98ffdbffd207"}
{"status":"Download complete","progressDetail":{},"id":"98ffdbffd207"}
{"status":"Download complete","progressDetail":{},"id":"98ffdbffd207"}

I think docker cli and podman-remote are other stories, and they just do smart output tweaking. What I was doing I was just taking care of REST API. I will look at how to make it better in podman-remote as well.

In order to render progress bars we need to know a number of things:
What is being copied (e.g., config, blob)
What is the total size
How much data has been copied

I am using ProgressProperties structure which is emitted and all of it it's already there.

Thanks a lot for looking into this, @jmguzik, I appreciate your help!

No problem @vrothberg , the only constrain is time :)

@mtrmac
Copy link
Collaborator

mtrmac commented Jul 12, 2022

  • The output of podman pull and podman-remote pull should be identical

My purely personal opinion is that as long as we don’t make any promise of output stability, we don’t quite need to insist on this part.

That said, if we were going for this, it’s an interesting question whether the MPB-drawn progress bars can be streamed over the network. It might actually be easier to do that than to extend types.ProgressProperties to represent all of the underlying data some other way. Right now, forwarding MPB progress bar output immediately runs into the copy.Image condition that only draws progress bars to a TTY ReportWriter. That could be changed or, in the worst case, bypassed by running a pseudo-TTY. To me, forwarding MPB feels like an attractive avenue to investigate.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 12, 2022

That said, if we were going for this, it’s an interesting question whether the MPB-drawn progress bars can be streamed over the network.

@mtrmac I have never seen the possibility of sending via REST API stream of TTY-like output. Docker is sending json properties and progressBar as a string. A true REST expert would need to answer this question.

It might actually be easier to do that than to extend types.ProgressProperties to represent all of the underlying data some other way.

I think types.ProgressProperties has right now everything to reconstruct the message in place.

Right now, forwarding MPB progress bar output immediately runs into the copy.Image condition that only draws progress bars to a TTY ReportWriter. That could be changed or, in the worst case, bypassed by running a pseudo-TTY. To me, forwarding MPB feels like an attractive avenue to investigate.

I started the issue with the purpose of changing the REST API endpoint because the issue was originally stated like that. That is why I did not fully understand at the time all comments about copy.Image. @vrothberg added podman-remote to the picture, no problem with that.
My next step would be to check how actually docker client interprets REST calls. I strongly believe it is just reconstructing it from the JSON structure in place, yet it needs to be confirmed. MPB feels attractive also because it's implemented, but I doubt it can be jsoned easily.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 13, 2022

@vrothberg it is still WIP, but I think it's the best I can do at the moment:
https://user-images.githubusercontent.com/78746728/178688033-5c217140-b1eb-4134-973e-6530059bac32.mp4

I used an implementation similar to docker-cli, which is a message reconstruction. There is no clear way to send MPB progress bar via json. I used types.ProgressProperties which are also emitted.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 13, 2022

The code is not ready yet, but before polishing I need to ask if that output will be accepted.

@vrothberg
Copy link
Member

We cannot merge it as is as it's screwing the output of podman-remote pull, see below:

podman (progress) $ ./bin/podman-remote pull nginx
Resolved "nginx" as an alias (/home/vrothberg/.cache/containers/short-name-aliases.conf)
Trying to pull docker.io/library/nginx:latest...
Getting image source signatures
Copying blob b138da793ac8 pulling fs layer
Copying blob b9ed43dcc388 pulling fs layer
Copying blob b138da793ac8 done
Copying blob 650d8b758441 pulling fs layer
Copying blob a96aaf9a9ec3 pulling fs layer
Copying blob bb1705539683 pulling fs layer
Copying blob b9ed43dcc388 done
Copying blob 461246efe0a7 pulling fs layer
Copying blob 650d8b758441 done
Copying blob bb1705539683 done
Copying blob a96aaf9a9ec3 [========================================>          ]  20.32MB/25.35MB
Copying blob 461246efe0a7 [================>                                  ]  10.11MB/31.37MB
Copying blob a96aaf9a9ec3 done
Copying blob 461246efe0a7 [=================================================> ]  30.77MB/31.37MB
Copying blob 461246efe0a7 done
Copying config sha256:41b0e86104ba681811bf60b4d6970ed24dd59e282b36c352b8a55823bbb5e14a
Copying blob 41b0e86104ba pulling fs layer
Copying blob 41b0e86104ba done
Writing manifest to image destination
Storing signatures
41b0e86104ba681811bf60b4d6970ed24dd59e282b36c352b8a55823bbb5e14a

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 13, 2022

@vrothberg

The code is not ready yet, but before polishing I need to ask if that output will be accepted.

To consult new proposed output please see attached media: https://user-images.githubusercontent.com/78746728/178688033-5c217140-b1eb-4134-973e-6530059bac32.mp4

Copy link
Member

@vrothberg vrothberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @jmguzik !

@@ -36,6 +38,7 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
AllTags bool `schema:"allTags"`
PullPolicy string `schema:"policy"`
Quiet bool `schema:"quiet"`
Progress bool `schema:"progress"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new parameter needs wiring in pkg/api/server for the Swagger docs and wiring for podman-remote (and pkg/bindings).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, wait, it's old code :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just trying to consult output. Changes are mine local for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will have a new param though, so these updates will be needed.

@vrothberg
Copy link
Member

@vrothberg

The code is not ready yet, but before polishing I need to ask if that output will be accepted.

To consult new proposed output please see attached media: https://user-images.githubusercontent.com/78746728/178688033-5c217140-b1eb-4134-973e-6530059bac32.mp4

This looks great!

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 13, 2022

Still, WIP, pushed the general idea though.

@jmguzik jmguzik changed the title Additional progress info when pulling images via libpod endpoint [WIP] Additional progress info when pulling images via libpod endpoint Jul 13, 2022
@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 13, 2022
@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 13, 2022

/hold

@openshift-ci openshift-ci bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 13, 2022
Copy link
Member

@vrothberg vrothberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should take a step back and define what the goal is in this PR. The design/outcome has changed quite a bit.

I see two issues we should solve, probably in separate PRs.

1) Progress data

We already chatted about whether the PR solves #12341 or not. If non podman-remote users want to be able to render progress, then this PR is not enough. In order to achieve that goal, sometthing similar to types.ProgressProperties could be part of the returned status. To remain backwards compatible, returning such data should be opt-in via a new parameter. Users are then free to interpret the data as they want to.

2) Rendering progress in podman-remote

Currently podman-remote does not render any progress but merely prints a line indicating that a a blob/config is being copied. To properly render progress, we could use the progress data of 1) OR we could explore whether it's possible to render the progress bars from c/image directly over the wire as suggest by @mtrmac in #14886 (comment).

I prefer to tackle the two issues separately.

@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v4/pkg/inspect"
"github.com/containers/podman/v4/pkg/trust"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/jsonmessage"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's copy the type over here. This way we have full control and avoid potential silent regressions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vrothberg what do you mean by copy? Move it to podman, the whole file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the type(s) and methods that are needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is also used in compat API. Are you sure you want to move and leave there untouched?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks for double checking. The reasoning for the compat API is to remain compatible and follow the types.

For libpod, we should control the types.

case e := <-progress:
switch e.Event {
case types.ProgressEventNewArtifact:
report.Status = "pulling fs layer"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer keeping the status empty to be closer to how the local client looks like.

// Progress contains detailed information about download progress
Progress *jsonmessage.JSONProgress `json:"progressDetail,omitempty"`
// Status contains a short progress description
Status string `json:"status,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In it's current form, I consider this to be a breaking change. Previously, all data was part of Stream. Now the data is scattered across Stream and Status. If a podman-remote prior to this change pulls from the new service the output looks as follows:

^Cpodman (main) $ ./bin/podman-remote rmi -af && ./bin/podman-remote pull nginx                                                                 
Resolved "nginx" as an alias (/home/vrothberg/.cache/containers/short-name-aliases.conf)                                                        
Trying to pull docker.io/library/nginx:latest...                                                                                                
Getting image source signatures                                                                                                                 
Copying blobCopying blobCopying blobCopying blobCopying blobCopying blobCopying blobCopying blobCopying blobCopying blobCopying blobCopying blob
Copying blobCopying blobCopying configCopying configWriting manifest to image destination                                                       
Storing signatures                                                                                                                              
41b0e86104ba681811bf60b4d6970ed24dd59e282b36c352b8a55823bbb5e14a                                                                                

That means, unless we find a backwards compatible way, rendering the progress must be opt-in. Older clients must continue working with newer servers (unless the major versions differ).

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

1) Progress data

We already chatted about whether the PR solves #12341 or not. If non podman-remote users want to be able to render progress, then this PR is not enough. In order to achieve that goal, sometthing similar to types.ProgressProperties could be part of the returned status. To remain backwards compatible, returning such data should be opt-in via a new parameter. Users are then free to interpret the data as they want to.

That can be easily done. I can do that in this PR. I considered the previous approach to be a bug and did not take into account old clients.

2) Rendering progress in podman-remote

Currently podman-remote does not render any progress but merely prints a line indicating that a a blob/config is being copied. To properly render progress, we could use the progress data of 1) OR we could explore whether it's possible to render the progress bars from c/image directly over the wire as suggest by @mtrmac in #14886 (comment).

I prefer to tackle the two issues separately.

I do not get the second comment. I implemented the progress bar in podman-remote in this PR the way I showed in the video: https://user-images.githubusercontent.com/78746728/178688033-5c217140-b1eb-4134-973e-6530059bac32.mp4
You can't do better than that over JSON structures. The way proposed by @mtrmac is not possible in my opinion and used the progress data approach which is also used in docker. Later it can be shared with push as well.

@vrothberg
Copy link
Member

1) Progress data

We already chatted about whether the PR solves #12341 or not. If non podman-remote users want to be able to render progress, then this PR is not enough. In order to achieve that goal, sometthing similar to types.ProgressProperties could be part of the returned status. To remain backwards compatible, returning such data should be opt-in via a new parameter. Users are then free to interpret the data as they want to.

That can be easily done. I can do that in this PR.

Awesome, thanks! Let's discuss which data is needed. Shall we just include the entire ProgressProperty from c/image?

I think all of the data in the struct can be of use for clients.

@mtrmac @jwhonce @rhatdan WDYT?

2) Rendering progress in podman-remote

Currently podman-remote does not render any progress but merely prints a line indicating that a a blob/config is being copied. To properly render progress, we could use the progress data of 1) OR we could explore whether it's possible to render the progress bars from c/image directly over the wire as suggest by @mtrmac in #14886 (comment).
I prefer to tackle the two issues separately.

I do not get the second comment. I implemented the progress bar in podman-remote in this PR the way I showed in the video: https://user-images.githubusercontent.com/78746728/178688033-5c217140-b1eb-4134-973e-6530059bac32.mp4 You can't do better than that over JSON structures. The way proposed by @mtrmac is not possible in my opinion [...]

Can you elaborate? I think that it's possible when hijacking the connection, similar to what we're doing in attach.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

Can you elaborate? I think that it's possible when hijacking the connection, similar to what we're doing in attach.

So, I don't know anything about the hacky method of hijacking connection (is it still REST?). How then present the output to pure REST API users?

I can elaborate on what is actually implemented right now and I think it adds nicely to the data gathered from c/image.
c/image forwards to streams, the first is properties and the second one is the stream used for clients. I extended ImagePullReport to later reconstruct the message in the client. To reconstruct it, I used an approach similar to the one used in docker which serializes JSON struct in the server and then does output manipulation at the client side (the more or less similar thing is in docker-cli). That way everyone is satisfied:

  1. REST users will get additional data with progress,
  2. podman-remote users will get status.
  3. The same method can be applied to push feature which also lacks a proper progress bar.

Just as a side note @vrothberg I started this feature as only targeting REST API, I did not take into account podman-remote. I am not aware of any method to stream progress bars via JSON other than implemented, but also I am not an expert in the field.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

To properly render progress, we could use the progress data of 1)

It's implemented in this PR as described above. Have you tried compiling this branch to see and used associated podman-remote? Maybe there is a bug and/or misunderstanding here and we have different outputs.

@vrothberg
Copy link
Member

To properly render progress, we could use the progress data of 1)

It's implemented in this PR as described above. Have you tried compiling this branch to see and used associated podman-remote? Maybe there is a bug and/or misunderstanding here and we have different outputs.

Yes, I tried. It looks much better than the status quo but I am not yet sure that's what we should do. Once we explored the idea of hijacking the connection and let c/image render, we can check again.

Focusing on 1) only in this PR will be a huge leap forward.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

Yes, I tried. It looks much better than the status quo but I am not yet sure that's what we should do. Once we explored the idea of hijacking the connection and let c/image render, we can check again.

Focusing on 1) only in this PR will be a huge leap forward.

@vrothberg maybe it's not an argument for you, but docker also has a hijacking connection for attaching and it's still using the presented method to do the push/pull data manipulation. I also had the feeling that we applied OR condition here so I have chosen something I believe it's better suited for this use case. I consulted the output and thought it was OK.

Due to a lack of time, I won't be able to pursue a "hijacking" connection. It is too big a feature for me to handle and it may result in returning to this PR (docker as an example). I can leave it for somebody else to explore. My idea for image push was the same so I would also unassign myself from the issue.

From my point of view I would need some information from maintainers/approvers because I am confused about what to do next:

  1. Should I close this PR?
  2. If not what should what should we do next:
    a) Do you want to merge the proposed method to "have something" until somebody reaserch the "hijacking"?
    b) Do you want to get rid of the proposed method and just leave REST JSON structures as part of the PR?
  3. Some 3rd option?

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

types.ProgressProperties is converted to jsonmessage.JSONProgress. I attached everything that has a value for the user there. I believe types.ProgressProperties is not the struct you want to transfer over JSON as it has other data not necessary useful to the end user. I am now confused about the PR... I think i do not understand the direction and what is expected to be achieved.

@vrothberg
Copy link
Member

I am now confused about the PR... I think i do not understand the direction and what is expected to be achieved.

I think this PR should implement 1) but 1) and 2) are/can be conceptually different things.

types.ProgressProperties is converted to jsonmessage.JSONProgress. I attached everything that has a value for the user there. I believe types.ProgressProperties is not the struct you want to transfer over JSON as it has other data not necessary useful to the end user.

If we stick with 1) types.ProgressProperties has IMO a number of benefits. Most importantly, we control and maintain the data structure. It also contains (media) type information of the blobs so caller can interpret it accordingly. Cockpit, for instance, is free to render the progress bars in javascript or in whatever way they chose to. This is not something a user would face but be interpreted by a machine.

However, 2) is something a user would face. I totally understand the desire to do what Docker does and render the progress bar client side. Docker had a client-server architecture from the very beginning that Podman had not for a long while. Hence, the progress bars are rendered server side. We could for sure go hybrid and have both but that comes at the cost of code duplication which is painful long term when adding new features or fixing bugs. Hence, I think we have the choice between a) consolidating the progress-bar code in c/image/copy to something for outside callers OR b) hijacking the connection. In this case, b) seems much more attractive to me.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

Hence, I think we have the choice between a) consolidating the progress-bar code in c/image/copy to something for outside callers OR b) hijacking the connection. In this case, b) seems much more attractive to me.

@vrothberg no problem, so I would leave the code here and close this PR. I leave a comment in the issue for somebody else to continue so that he/she knows the progress was made but options a), b) is needed to be explored.

Regarding 1) if you make a decision with @mtrmac @jwhonce @rhatdan I can open a new PR and do this work, but I am skeptical about the structure. I think there is no problem with doing something similar to jsonmessage.JSONProgress to be maintained by you guys, but types.ProgressProperties is not a user-friendly structure at all, even for REST. I may lack a bigger picture though.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

consolidating the progress-bar code in c/image/copy to something for outside callers

This will ultimately lead to this solution since you still need to reconstruct progress from the structs. Going this way there is no different outcome.
So I recommend whoever takes this adventure to start with option b) not to reinvent the wheel again 🙂

@mtrmac
Copy link
Collaborator

mtrmac commented Jul 18, 2022

I think that it's possible when hijacking the connection, similar to what we're doing in attach.

Assuming “hijacking” refers to fundamentally changing the nature of the TCP socket, is that actually necessary?

The start of the issue quotes a sequence of JSON objects in the response. So, couldn’t we just add one more type, e.g.

{"tty-stream":"${escape-sequence}Copying blob {escape-sequence}sha256:a1dd213a3236752eb500bedc1296fcd8b9485906292cb9a358cba5c0c38ded31{escape-sequence}"}
{"stream":"Copying blob sha256:a1dd213a3236752eb500bedc1296fcd8b9485906292cb9a358cba5c0c38ded31\n"}

freely intermixed with the existing output? Is that a compatibility problem because old clients couldn’t handle that, or something?

(That said, streaming TTY escape sequences is not trivial either. One has to worry about $TERM, window sizes, and so on. And Cockpit and the like would definitely benefit from well-structured data much more than about old vt100-like fixed-column output.)

@mtrmac
Copy link
Collaborator

mtrmac commented Jul 18, 2022

consolidating the progress-bar code in c/image/copy to something for outside callers

This will ultimately lead to this solution since you still need to reconstruct progress from the structs.

Right now, c/image is producing the typed data and the progress bars using somewhat unrelated code paths. Changing that seems conceptually attractive, but it’s not something that exists and can just be made public for podman-remote use right now.

@vrothberg
Copy link
Member

I think that it's possible when hijacking the connection, similar to what we're doing in attach.

Assuming “hijacking” refers to fundamentally changing the nature of the TCP socket, is that actually necessary?

That's how attach deals with the terminal issues among other things. Maybe there is an alternative that I don't know.

The start of the issue quotes a sequence of JSON objects in the response. So, couldn’t we just add one more type, e.g.

{"tty-stream":"${escape-sequence}Copying blob {escape-sequence}sha256:a1dd213a3236752eb500bedc1296fcd8b9485906292cb9a358cba5c0c38ded31{escape-sequence}"}
{"stream":"Copying blob sha256:a1dd213a3236752eb500bedc1296fcd8b9485906292cb9a358cba5c0c38ded31\n"}

Would that render the progress bars?

freely intermixed with the existing output? Is that a compatibility problem because old clients couldn’t handle that, or something?

Yes, that would break compatibility in the sense that it'll screw the output for older clients. That's why I think it should be opt-in - which is an easy and cheap "get free out of fail" card.

(That said, streaming TTY escape sequences is not trivial either. One has to worry about $TERM, window sizes, and so on. And Cockpit and the like would definitely benefit from well-structured data much more than about old vt100-like fixed-column output.)

I concur.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

That's how attach deals with the terminal issues among other things. Maybe there is an alternative that I don't know.

I still wonder why docker people did not follow that. They also have attached, yet they are not using the method for streaming the progress bar. Unfortunately, tracing the rationale would take some time, which I can't spend 😞

@vrothberg
Copy link
Member

That's how attach deals with the terminal issues among other things. Maybe there is an alternative that I don't know.

I still wonder why docker people did not follow that. They also have attached, yet they are not using the method for streaming the progress bar. Unfortunately, tracing the rationale would take some time, which I can't spend disappointed

I assume because the initial architecture of Docker has always been a client-service model. I think it's much more attractive to do it the Docker-way from a purity/design point of view.

But we have to balance the cost-benefit ratio where "hijacking" seems more attractive to me than a potentially long rewrite of a number of code paths.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

But we have to balance the cost-benefit ratio where "hijacking" seems more attractive to me than a potentially long rewrite of a number of code paths.

I found a few moments to look at attach. IMHO adding it here to support progress bar use case seems like over engineering. The presented change will not result in rewriting many paths and it will keep backwards compatibility with no additional arguments, while hijacking seems to not be the same in that regards, adding additional complexity only to get progress bars.
It's my opinion though and I respect your decision. I remain available in the future if you want to continue following the path layed out in this PR.

Right now, c/image is producing the typed data and the progress bars using somewhat unrelated code paths. Changing that seems conceptually attractive, but it’s not something that exists and can just be made public for podman-remote use right now.

Is it really worth to merge them since there is possibility to handle them both? If the statement is to support hijacking than I do not understand how it would change the situation. If it's a general comment I don't think it's worth investing the effort. Again, it's my opinion and i may not know everything 🙂

@mtrmac
Copy link
Collaborator

mtrmac commented Jul 18, 2022

(I find hijacking unattractive. We can just extend the existing JSON, for any kind of data, AFAICS. We are not contemplating an interactive TTY emulation where we would need to also support passing input to the server.)

Is it really worth to merge them since there is possibility to handle them both?

That rather depends on how strongly Podman insists on keeping exactly the same progress bar output for local and remote. I don’t think the consistency is actually that valuable (the network might be slow and high-latency, so the remote case should. IMHO, optimize of less frequent updates over elegant animations [the default is 6.6 Hz]), but if the desire is to stay consistent, the only truly maintainable way to do that is to only have one implementation that draws the progress bars shared between the local and remote cases, and one shared implementation implies one shared format of data input.

@BlaineEXE
Copy link

FWIW, as a requester of this feature, I don't think it's necessary to keep the exact same progress bar output. From my staindpoint, the progress output is for interactive, human-readable sessions, and I just want to see the general progress and make sure things aren't stuck.

I don't see why anyone would write scripts around the progress bars. Scripting should be done via return codes and formatted output like JSON.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jul 18, 2022

(I find hijacking unattractive. We can just extend the existing JSON, for any kind of data, AFAICS. We are not contemplating an interactive TTY emulation where we would need to also support passing input to the server.)

+1

Is it really worth to merge them since there is possibility to handle them both?

That rather depends on how strongly Podman insists on keeping exactly the same progress bar output for local and remote.

I actually looked from my user perspective. I want probably progress for bigger blobs. Whether the progress bar will fly slowly or quickly (in a matter of frequency) who cares. I know I am using podman-remote and a connection, so I just want to be informed about the progress.

I just think either merging two signals into one in c/image and/or doing hijacking for a simple progress bar seems overengineered approach. It's my personal opinion after spending some time around that feature as sniffing around what is implemented in docker. I also do not see the argument of hijacking being maintainable. I looked at the code and it's not easy to digest at first glance, while simple output manipulation is (unit testing is actually implemented there to check consistency and can be generalized to serve both push/pull).

@jmguzik
Copy link
Contributor Author

jmguzik commented Aug 5, 2022

@mtrmac @vrothberg I just want to ask after some time if you had some internal talks to design doc the approach or if any other progress was made.
Maybe, I could just open a PR which will handle this issue for rest api only, not affecting podman-remote at all... Would that be less controversial?

@vrothberg
Copy link
Member

Thanks for reaching out, @jmguzik. I'd feel more comfortable if we had a design doc first.

@jmguzik
Copy link
Contributor Author

jmguzik commented Jan 10, 2023

@vrothberg just found again this issue while searching for something else. I thought I just ping to ask if there is any recent development around version choosing or design doc for this one.

@vrothberg
Copy link
Member

@vrothberg just found again this issue while searching for something else. I thought I just ping to ask if there is any recent development around version choosing or design doc for this one.

Thanks for reaching out. I fear that there is no development on this issue yet.

@github-actions github-actions bot added the locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. label Sep 15, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. release-note
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[API] No way to obtain image pull progress
4 participants