-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
[WIP] load/save oci-archive multi images #8218
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: QiWang19 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 |
img := imageMap[id] | ||
copyOptions := getCopyOptions(sys, writer, nil, nil, SigningOptions{RemoveSignatures: removeSignatures}, "", img.tags) | ||
copyOptions.DestinationCtx.SystemRegistriesConfPath = registries.SystemRegistriesConfPath() |
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.
need table format
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.
Early feedback from testing:
We need to distinguish IDs from names. Currently, IDs are treated as names and stored in annotations which leads to:
$ podman load -i ...
Loaded image(s): localhost/79fd58dc7611, localhost/d6e46aa2470d
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.
I dropped some comments on the c/image PR: containers/image#1072 (review)
I think there are two things we need to address:
- We need to support multiple names or none.
- We need/should be consistent with the reference syntax of docker-archive which identifies images by index: https://github.com/containers/image/blob/master/docs/containers-transports.5.md#docker-archivepathdocker-referencesource-index
b0d6409
to
62ec555
Compare
7a24e9b
to
bfb9c0b
Compare
88cd693
to
4987527
Compare
@containers/podman-maintainers @vrothberg @mtrmac PTAL |
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.
From a very quick skim, this results in a very large function that is going to be very hard to maintain (just read, but primarily keep consistent). It would be nice to share more of the format-independent infrastructure.
Most importantly the namesOrIDs
parsing code should be shared if at all possible, to ensure the semantics of that parameter is consistent across archive formats — even if the actual copy implementation needs to be different because one can benefit from DockerArchiveAdditionalTags
. But also the things like converting imageNames
to newImages
would probably benefit from sharing (or, well, eliminating; the copy already has a storage reference so converting it into a name and back is pointless extra work), and I worry a bit about newImageEvent
which is not mechanically essential, it might be too easy to forget to update a copy.
(Very tentative: it might be worth splitting the archive save/load code, along with the archive-specific helpers, into a separate file that can be easier to understand as a whole — if you do that, please make it a separate commit that changes nothing in the code.)
libpod/runtime_img.go
Outdated
newImages, err = r.ImageRuntime().LoadAllImagesFromOCIArchive(ctx, inputFile, signaturePolicy, writer) | ||
if err == nil { | ||
return getImageNames(newImages), nil | ||
} |
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.
These “try N different formats, succeed on any one” functions have frequently caused user confusion.
- Would it make sense to have the user specify the format? I guess auto-detection is a desirable feature…
- The error reporting definitely needs improving. If the user submits a docker-archive format that is mostly (or completely) valid but the load fails, the docker-archive-related error must be available to the user.
- (Extra thought, probably not for this PR: It might be interesting to have an “autodetect archive format” helper so that we can detect the format separately (or report a clear error that the format is unrecognized), and then just do one load attempt with a simple error reporting structure. Or, well, we could go even further and share a single “decompress and untar” operation across all formats — right now we would decompress the multiple gigabytes separately for each format.)
- … actually, the fact that we have to decompress the multiple-gigabyte archive in every format until we find one that works is a pretty big cost, and IMHO a fairly strong reason to at least allow the user to specify the format, even we still wanted to support auto-detection.
35916a5
to
82ecd25
Compare
Conflicting files
|
82ecd25
to
1977368
Compare
1977368
to
11a49f2
Compare
541e99c
to
5c23ecf
Compare
@mtrmac PTAL, Added an archivehelper to decide the format according to the manifest.json to index.json, it this a way to detect the format? |
That’s a neat idea, for the cases where this code does work it’s cheap enough, and for the expensive case (compressed archive) we can just not do that much work to guess. But because it can fail, AFAICS there still must be the fall-back logic to try all of the formats (well, all of the archive formats or all of the directory formats, no need for both). |
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.
I’m still rather unhappy about the length and duplication in Runtime.SaveImages
, see earlier.
As mentioned a few times, if the guessing can fail, this still needs to try the relevant alternatives. Maybe the guessing could be a separate performance feature PR, I’m not sure whether that would help or hinder.
libpod/runtime_img.go
Outdated
return getImageNames(newImages), nil | ||
// imageFormat detects the image foramt of the input archive or directory | ||
// returns "", if can not decide the format | ||
func imageFormat(inputFile string) (string, error) { |
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.
guessImageFormat
maybe, to emphasize that it can fail to make a decision?
libpod/runtime_img.go
Outdated
// imageFormat detects the image foramt of the input archive or directory | ||
// returns "", if can not decide the format | ||
func imageFormat(inputFile string) (string, error) { | ||
path, err := explicitfilepath.ResolvePathToFullyExplicit(inputFile) |
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.
Does this do anything that matters for this function?
libpod/runtime_img.go
Outdated
if err != nil { | ||
return "", errors.Wrapf(err, "error detecting input file format") | ||
} | ||
if !archive.IsArchivePath(inputFile) { |
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.
An os.Stat
+ IsDir
would be a bit cheaper.
libpod/runtime_img.go
Outdated
break | ||
} | ||
if err != nil { | ||
return "", errors.Wrapf(err, "error detecting archive format") |
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.
Is this the path taken on a compressed archive? That should probably return "", nil
(and the caller must handle that) to indicate that it didn’t make a guess.
libpod/runtime_img.go
Outdated
if header.Name == "index.json" { | ||
return image.OCIArchive, nil | ||
} | ||
if header.Name == "manifest.json" { |
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.
Apparently for compatibility with some docker-archive
writers, path.Clean(header.Name)
must be used; I guess using it for both cases wouldn’t hurt.
format, err := imageFormat(inputFile) | ||
if err != nil { | ||
return "", err | ||
} |
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.
What if format can not be determined?
libpod/runtime_img.go
Outdated
return getImageNames(newImages), nil | ||
} | ||
return "", err | ||
|
||
return "", errors.Wrapf(err, "error pulling image") |
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.
This is incorrect if src == nil
(both “couldn’t guess” and “coding error”)
libpod/runtime_img.go
Outdated
} | ||
|
||
// LoadImageFromSingleImageDir loads image from the archive of single image that inputFile points to. | ||
func (r *Runtime) LoadImageFromSingleImageDir(ctx context.Context, writer io.Writer, inputFile, signaturePolicy, format string) (string, error) { |
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.
This can be package-private AFAICS.
libpod/runtime_img.go
Outdated
} | ||
return strings.Join(newImageNames, ", "), nil | ||
} | ||
return "", errors.Errorf("error loading multipal images from the archive") |
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.
This does not say much about why things failed or what the user should do.
return nil, errors.Wrapf(err, "error retrieving local image after pulling %s", name) | ||
} | ||
newImages = append(newImages, newImage) | ||
} |
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.
Nice.
Absolutely non-blocking: If I’m checking correctly, doing the same to LoadFromArchiveReference
would allow most of the Load
functions involved in this PR to return []string
, and two of the callers of Runtime.LoadImage
would eliminate a strings.Split
(and the third one would now contain the only strings.Join
).
(The detection is definitely useful, but not something I think must be in this PR; originally I only asked for not throwing away errors from all the attempts. If detection can fail and we still might end up guessing, the “not throwing away errors” part will continue to be necessary.) |
1698b8f
to
9d034a5
Compare
need gofmt the files |
9d034a5
to
ccbd8ce
Compare
@mtrmac Dropped the format detection from this PR. And the collections of the errors from |
@QiWang19 needs rebase. |
ccbd8ce
to
65565fb
Compare
still have |
This can not be merged as-is because it vendors an unmerged c/image branch, so that’s not an urgent concern at this point. |
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.
ACK in broad strokes, mostly “local” suggestions.
libpod/runtime_img.go
Outdated
) | ||
appendErr := func(e error) { | ||
if latestErr != nil { | ||
latestErr = errors.Wrapf(latestErr, "error pulling images: %v\n", e) |
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.
This will prefix some errors but not all? If I am reading this correctly,
error pulling images: error pulling images: error1
error2
error3
s/latestErr/allErrors/
maybe?
Most importantly, compare pkg/errorhandling
, or maybe use it. I don’t know what are all of the coding conventions in Podman, but this does look like a problem appropriate for a common solution.
libpod/runtime_img.go
Outdated
src, err := referenceFn() | ||
if src, err = referenceFn(); err != nil { | ||
appendErr(err) | ||
} | ||
if err == nil && src != nil { |
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.
(This can now be an else if
to be a tiny bit clearer.)
libpod/runtime_img.go
Outdated
return newImages, nil | ||
} | ||
logrus.Warnf("Error trying pulling multi-arch images: %v", err) |
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.
- s/multi-arch images/multi-image archives/
- For some formats like
dir
,LoadAllImageFromArchive
will not even try, so it’s grating to output a warning and then succeed. - This is the only caller of
LoadAllImageFromArchive
as well asLoadImageFromSingleImageArchive
, so it seems that there should only be one set of attempts, one list of errors (and the two archive formats should only be attempted once, not once via the multi-image reader and once via the non-reader path).
libpod/runtime_img.go
Outdated
if err == nil { | ||
return strings.Join(newImageNames, ", "), nil | ||
} | ||
appendErr(errors.Wrapf(err, "error trying multi docker aechive")) |
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.
“archive”, and this probably could benefit from a bit of rewording (users don’t care much about the “multi” part) — I haven’t tried this to see what the eventual full error text looks like.
(In both cases).
libpod/image/image.go
Outdated
@@ -244,48 +240,143 @@ func (ir *Runtime) SaveImages(ctx context.Context, namesOrIDs []string, format s | |||
if isTagged { | |||
iData.tags = append(iData.tags, refTagged) | |||
} | |||
} else { | |||
iData.destNames = []string{""} |
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.
This shouldn’t throw away any previous tags. Maybe add a single imageSpecifiedByID
boolean?
libpod/image/image.go
Outdated
// extend an image with additional tags | ||
type imageData struct { | ||
destNames []string |
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.
If “extend an image”, the *Image
should probably remain first.
I’m not 100% happy with the two duplicate name arrays, but I also can’t see much of an alternative. (Moving the docker-archive tag parsing into the docker-archive specific loop would probably add too much complexity.)
img := imageMap[id] | ||
// For copying, we need a source reference that we can create | ||
// from the image. | ||
src, err := is.Transport.NewStoreReference(img.imageruntime.store, nil, id) |
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.
This lookup can AFAICS also happen in the shared imageQueue
construction code.
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.
The src, storageReference
is not exported. The imageQueue may not be able to hold a field for it.
65565fb
to
852ed98
Compare
Allow load/save oci-archive format multi images. Signed-off-by: Qi Wang <[email protected]>
Signed-off-by: Qi Wang <[email protected]>
852ed98
to
45e424a
Compare
@mtrmac PTAL |
A friendly reminder that this PR had no activity for 30 days. |
@QiWang19: PR needs rebase. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
@QiWang19, do you still have time to tackle it? No worries in case not. I am going through some open PRs and issues at the moment. |
Yes, I will find time to rebase this one and cooperate it with containers/image#1072. |
Closing the PR as it must now be addressed in c/common/libimage. Thanks, @QiWang19, for working on this! |
Allow load/save oci-archive format multi images.
close #4646
Signed-off-by: Qi Wang [email protected]