-
Notifications
You must be signed in to change notification settings - Fork 858
proxy: Add GetRawBlob #2601
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
proxy: Add GetRawBlob #2601
Conversation
Draft since this works well for me, but needs tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
- The part where the size is not required LGTM — I don’t remember how it happened that the size is ~never used in c/image (note to self, apart from
blobCacheSource
). We should note that in the c/image documentation to guide possible future API redesigns. - I don’t understand how moving the digest verification significantly helps.
- If nothing else, after removing the error reporting mechanism a consumer won’t be able to differentiate between a (retryable) network error and a digest validation error. Admittedly, currently the proxy error handling mechanism doesn’t allow cleanly differentiating that anyway, but this removes the option of improving that.
- I don’t understand how this helps at the Rust client side. Assuming the digest verification moves to the Rust side (*shrug*), there is something like
AsyncRead
which returnsasync StreamOfBytesOrError
providing a digest-validated byte stream. It seems to me that the Rust client side can trivially callFinishPipe
at the place where it would do the digest verification, what’s the difficulty?! Some kind of Rust-related reference counting making it hard to hold on to a proxy handle at that time? - And if
FinishPipe
remained, I don’t see much of a reason to prefer the digest verification happening at one side or the other, except perhaps that sha512 digests are coming, and that will be transparently handled with the Go code as is.
Forgot to mention in this PR but this is a dependency of https://github.com/cgwalters/cstor-dist which you may also be interested in |
Sorry the issue with more real discussion is bootc-dev/containers-image-proxy-rs#80 which TL;DR is that it's a problem that Which we could definitely also fix without
Yes it'd be really nice to handle that indeed. I guess a possible design here would be
or so? (Framed in something like bincode since json is pretty suboptimal for binary data) I guess this whole thing quickly goes back to less-ad-hoc IPC frameworks. |
Do I understand it correctly that there is thread A consuming the blob, and thread B calling After A finishes consuming data, (Even with a design where the proxy is all “owned” by a single proxy client thread, making it undesirable for thread A to make requests directly, having A communicate to the proxy client and block on a reply might not be that much worse? It does serialize everything at the proxy client, but that would be ~equivalent in effect to the serialization that happens in the proxy server anyway.) There is a potentially real issue here in that
Yes.
And that too. |
Yeah I think you're right. We could probably just automatically handle this in the rust client code. So it's not a strong argument for
Note for the use case of cstor-dist we're going: And it'd be silly to have cstor-dist also do checksum verification because we know the client is going to do it. So probably regardless IMO some sort of
I think any nontrivial consumer of the proxy is going to be parsing the manifest digests and doing things with them. The ostree and composefs-rs projects definitely are and so there's no magic adaptation. |
Anyways though, the other option is to just cut the size requirement for |
Yes, that’s a good enough reason.
Yes, allowing -1 through should work fine. |
… to allow the client to opt out of digest verification, somehow. I’m not too convinced about removing the error handling entirely. |
But in the raw case the error handling is literally just whether or not the proxy successfully wrote to the pipe, right? Which, most often is actually an Which, the only way to fix that sanely I think is to have a new API creatively called
It returns...umm, I am vacillating on what the format should be. I tried hard so far to only make this thing about JSON and So what gets sent over the error fd would be at most one of:
But we'd need to bikeshed how
(And yes we should probably emit an error if we get |
Just a note on this part for now:
On an error reading from the registry, it’s the full information the Go server side has: “connection reset / unexpected EOF /
Note to self: Return here. We’ve had
It’s hard, in the corner cases, even within a single-language process :) There’s ample space to over-engineer. I think the above is a good start, and we can always add The extreme is to adopt something like https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties , where the error can have an open-ended list of non-exclusive bools (“network-related”? “retryable”? “timeout”? All 3 could be true simultaneously). I think that’s overkill. I think it would be convenient to use the same error mechanism for the current |
Ref. containers/storage#2162 : If there is a A single pipe is easier to consume and reason about. |
One possible way to think about this is that consuming two pipes requires the caller to always read the error pipe until EOF; that’s probably not any easier than, in the current API, calling |
Right, but that's easy? I mean at least in Rust I'd map this as two futures which both need to be joined, not a
Mmmmm...except the problem again with today's API is that the client doesn't get EOF until it calls |
Oops, I have completely missed that when discussing this PR. That makes many of the things I suggested above, thinking that they are simple, rather less practical.
[ … does error reporting work at all if there is a network error in the middle of a blob? The goroutine in Am I missing something again? If it does fail this way, then yes, we definitely need a new |
That doesn't matter though because we always know the expected size from the manifest descriptor and that's what clients should use, right?
Well, the way this is working right now is that the calling process in Rust creates two futures, one doing the read/processing and one calling It'd be really quite ugly but I suspect a viable hack for the status quo would be to only queue the FinishPipe on a timeout if we stop getting data from the pipe or so (and that happens before the expected size) |
schema1 manifests don’t have sizes. (OTOH at least Docker has been working for years to disable schema1 manifests, e.g. |
We hard error on that case today already. I honestly would actually like to add a |
OK I reworked this per discussion and also updated the example consumer in bootc-dev/containers-image-proxy-rs#83 - just got as far as verifying the example client there works. Could still use tests here etc. |
Tests failed. @containers/packit-build please check. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
ACK overall. (Note also the lint failures.)
b9267e8
to
4e797b4
Compare
Ephemeral COPR build failed. @containers/packit-build please check. |
0916ddf
to
62782cf
Compare
(It'd sure be nice if github had a "commit as fixup" button) |
The original model the idea here is the proxy centralizes verification of things like digest. However in practice, this causes reading to be seriously awkward; ref bootc-dev/containers-image-proxy-rs#79 (Basically `FinishPipe` blocks the metadata channel) Also, I have a project to implement a registry frontend to `containers-storage:` and a core problem with `GetBlob` right now is it *requires* the blob size up front even though the underlying Go logic doesn't. Moving to a "raw" interface solves that too. In this new raw API, we return two file descriptors, one for the data and one for the error channel, which contains a JSON serialization of an error. For the error type we reuse the existing "is error retryable" and expose that back to the client. We also (backwards compatibly) add this new error code for the existing APIs. Signed-off-by: Colin Walters <[email protected]>
Pre-existing problem noticed in review. Signed-off-by: Colin Walters <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
The original model the idea here is the proxy centralizes verification of things like digest. However in practice, this causes reading to be seriously awkward; ref
bootc-dev/containers-image-proxy-rs#79
Also, I have a project to implement a registry frontend to
containers-storage:
and a core problem withGetBlob
right now is it requires the blob size up front even though the underlying Go logic doesn't.Moving to a "raw" interface solves that.