-
Notifications
You must be signed in to change notification settings - Fork 546
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
v1/layout.WriteIndex ignores platform #817
Comments
I'm misunderstanding something. What should For AppendIndex, we just use that to populate the descriptor in |
It is easier if I describe it in an example. I pull down
It also will pull down the config for each of those platforms and all of the layers for all of those platforms. When I pass in |
Interesting. Let's say you pass in the amd64 platform. For Both Just All manifests, but only blobs for I think what you're trying to do, when pulling from a registry, would be, roughly: ref, _ := name.ParseReference("docker.io/library.alpine:3.11")
img, _ := remote.Image(ref, remote.WithPlatform(platform))
_ = path.WriteImage(img)
This feels a bit odd to me. Given the naming, I'd expect I would agree that the package global nature of options make them awkward to use, but the godoc for
Maybe we should update that to explicitly say "in index.json". What you're asking for reminds me of the sparse/thin idea for go-containerregistry/pkg/v1/layout/options.go Lines 5 to 9 in 6a63025
Something like: "I want to you to write this artifact to this image layout, but I only want to write certain parts." Depending on how many use cases we want a sparse option to support, we could come up with a signature that supports stuff like:
I'm tempted to close this as WAI, and if we're interested in pursuing something like this, we could pick this conversation back up: #651 (comment) |
Very good point. I missed that. Once we figure out the right flow, it probably would be a good idea to make this a little clearer, that it only affects what is written in
I expect it always to contain the root index, and the manifest for whatever platform I am trying to pull. In the above example:
I would always want to have the root index, so that the tag in I also becomes required if I later decide to pull another platform, e.g. arm64. The root index is unchanged, so what does Bringing this back to the starting point (or I am trying to :-) ), the behaviour I want is that I can get the root index for a particular tag, and then pull down just those blobs that start in the matching platform in that index. FYI, if there already is a way to do this, then this just becomes a documentation question. I don't think The correct flow does appear to be not filtering during the As I think about it, I might be able to do it as follows:
So the tools all are there, but it is messy. |
I am coming back at this, now that we have a fairly nice and clean My usual way of getting an index and its underlying images is something like this (largely informed by handholding from @jonjohnsonjr 😁): ref, err = name.ParseReference(image)
desc, err = remote.Get(ref, options...)
ii, err := desc.ImageIndex()
err = p.AppendIndex(ii, opts...)
// OR
err = WriteIndex(ii) legacy and v1 tarballs aren't an issue, since they only support single images. I think the simplest way forward here is to create an additional I would then create some a utility matcher for the single most common use case, i.e. that I want the index and any index children, but when I come to an actual image, match it to a particular platform. Like to get your feedback @jonjohnsonjr , and then we can get a PR in. |
This isn't actually true!
I'm terrified of what this package will look like with multiple sets of variadic options that apply to different methods 😄
I'd like to nail down the semantics of this option and make sure it satisfies a lot of use cases, is easy to understand, and easy to use. My intuition after half a bottle of wine is something like this: p.AppendIndex(ii, layout.WithMatcher(func(desc v1.Descriptor) bool {
if desc.MediaType.IsImage() {
return desc.Platform.Equals(platformYouCareAbout)
}
return true
})) But I don't think this is right. One implementation of I don't see a way to easily express the latter with this interface (beyond having a separate option to distinguish them... Of course we can always add an option to do the very specific thing that you need, but I'd like to be as generic as we can get away with... I'd be interested in any ideas if you have them. |
(FWIW, for your use case specifically, we could document that Write methods do |
Doesn't that violate CAP theorem? You can pick only 2 out of 3. 😂 |
That is a very good point. it is a reason why I haven't tried to tackle it yet. Actually, different options applied to different methods don't bother me too much, as each method can just use the ones it wants. The problem becomes, what do you do when they conflict. For example, is
I disagree with that statement. If I skip a manifest, I skip all children blobs. No matter how you do this, it should be a tree-walker or it is impossible to reason about. E.g. containerd will garbage-collect any blobs that do not have a parent, i.e. manifest/index. These all are trees, and a leave cannot exist without the branch it is on. Granted, you could explicitly download a specific blob, but that is beyond the scope of this discussion.
I agree. Although I think "filter by platform" already is generic enough to not be "very specific thing", but I would like a generic solution. I am going to put some ideas in the next comment. |
I keep coming back to your example above, and I actually think it works. p.AppendIndex(ii, layout.WithMatcher(func(desc v1.Descriptor) bool {
if desc.MediaType.IsImage() {
return desc.Platform.Equals(platformYouCareAbout)
}
return true
})) If we assume that as soon as I skip a node, I skip all of its children (which is eminently reasonable), then this works perfectly. If we really want to tackle the "skip a generation" case, I would suggest the following:
|
I run into something like this a lot where:
To achieve 2, now I have to reach around the API and write some really janky code. It would be great if I could reuse the nice tools and API to produce testdata for these "invalid" states. In this particular case it's frustrating because I agree with what you're saying 99% of the time, but the data structure doesn't explicitly forbid this kind of thing, so it's not really an "invalid" state.
I think I'm okay with this being a default assumption as long as it's clearly documented. If we come up with a use case where we only want to write blobs (or something like that), we can create a new, more oddly named option. I'm also okay with sacrificing the ergonomics of the 1% case in favor of the ergonomics of the 99% case. |
Good point. Well, we do have
I can open a PR for this one, let us see where it goes. |
I am a little stuck. I don't know how to make this part work: p.AppendIndex(ii, layout.WithMatcher(func(desc v1.Descriptor) bool {
if desc.MediaType.IsImage() {
return desc.Platform.Equals(platformYouCareAbout)
}
return true
})) The signature for func (l Path) AppendIndex(ii v1.ImageIndex, options ...Option) error where each option is: type Option func(*v1.Descriptor) error In if err := l.WriteIndex(ii); err != nil {
return err
}
// ...
for _, opt := range options {
if err := opt(&desc); err != nil {
return err
}
} Each option processes/modifies the final How would I pass an option that does not do that, but instead needs to send a |
Yeah we'll need to change the |
What would you change it into? I couldn't wrap my head around what the "new" |
Basically do what For the existing options, we'd need to thunk-ify them: #847 You can then add whatever you want to that |
This issue is stale because it has been open for 90 days with no |
Merged that, BTW. |
This issue is stale because it has been open for 90 days with no |
We don't check the platform option when calling
WriteIndex()
see here:This predates #815, as it was the same for
writeIndex()
. We do pass it to AppendIndex:where one
Option
isWithPlatform
, but we don't actually pass it through toWriteIndex
.Any objection to a PR to fix it?
The text was updated successfully, but these errors were encountered: