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

bug fix: handle CopySpecificImages correctly #1483

Closed
wants to merge 1 commit into from
Closed

bug fix: handle CopySpecificImages correctly #1483

wants to merge 1 commit into from

Conversation

philipp-rosenkranz-form3
Copy link

@philipp-rosenkranz-form3 philipp-rosenkranz-form3 commented Mar 4, 2022

Currently the ImageListSelection setting copy.CopySpecificImages in copy.Options is useless since any digest slice passed to Instances must have the same length as the slice of manifests in the source list.

Therefore, the only way to use copy.CopySpecificImages is to pass into Instances all digests which are present in the source list of manifests. Thus, copy.CopySpecificImages behaves like a really clunky version of copy.CopyAllImages.

This PR ensures that copy.CopySpecificImages is actually useful (again?) by removing any manifest from the list which cannot be matched with a digest listed in Instances.

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

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

Thanks for the PR.

For better or worse, the current implementation (essentially a sparse copy) is international (e.g. documented in skopeo copy --multi-arch=index-only). We can’t just break it.

A feature to strip the image of unwanted architectures (while still keeping it a multi-arch image, not just extracting a single architecture) does sound useful, but it would be a new feature. There’s also a more generic request to add manifest editing support (e.g. containers/skopeo#1136 ), and ideally we would want that to replace the c/common / Buildah / Podman implementations.

So that would be interesting, but a significantly larger work than this.

The need to keep the API of c/image stable is also a fairly significant constraint. One we can work with, but it requires more infrastructure, and thinking carefully about any new API additions.

@@ -33,6 +33,10 @@ type List interface {
// must be specified.
UpdateInstances([]ListUpdate) error

// UpdateInstancesAndDiscardOthers overrides the instances slice with information contained in the passed-in slice.
// All instances which do not have a matching digest in the passed-in slice will be discarded.
UpdateInstancesAndDiscardOthers([]ListUpdate) error
Copy link
Collaborator

Choose a reason for hiding this comment

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

I’m afraid we can’t just add new methods to interfaces, that’s an API break. We are building infrastructure to allow extending things (see c/image/internal/private), but that doesn’t currently cover manifest.List.

So this would end up being a significantly larger PR.

// the images we want to copy.
if len(copiedUpdates) < len(instanceDigests) {
updates = copiedUpdates
if err = updatedList.UpdateInstancesAndDiscardOthers(updates); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don’t see why we would pass the whole update to both UpdateInstancesAndDiscardOthers and to UpdateInstances below.

I don’t immediately know whether it makes more sense to have a single “edit + change set of instances” function, or to split that into edit/add/remove. UpdateInstancesAndDiscardOthers intuitively looks pretty far from a generic/orthogonal interface.

Note to self: Compare also the “manifest editing” implementation in Buildah, Podman, containers/common, to understand the problem space and necessary features.

Comment on lines +92 to +96
for _, u := range listUpdate {
if m.Digest == u.Digest {
existingManifest[u.Digest] = m
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

AFAICS this could unconditionally build existingManifest[m.Digest] = m; the entries to be removed would just be ignored. That turns this from O(N^2) into O(N).

Same in the other implementation.

}
list.Manifests = []Schema2ManifestDescriptor{}
for _, u := range listUpdate {
updatedManifest, ok := existingManifest[u.Digest]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don’t think this works at all in the case where the copy had to convert the format of the original manifest, so u.Digest doesn‘t match any pre-existing value in list.Manifests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants