-
Notifications
You must be signed in to change notification settings - Fork 246
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
Add names-history support #422
Conversation
@rhatdan @vrothberg @nalind @mtrmac WDYT? It is mainly another approach to improve the information density about images to end users without breaking past versions. |
I like it. What happens if I tag the image? If I can tag it, can I still push it? Can I remove it via tag name? |
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.
Sounds like a nice thing to have 👍
images.go
Outdated
@@ -492,6 +504,7 @@ func (r *imageStore) SetNames(id string, names []string) error { | |||
} | |||
for _, name := range names { | |||
if otherImage, ok := r.byname[name]; ok { | |||
r.addNameToHistory(otherImage, name) |
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 suggest calling addNameToHistory(...)
from removeName(...)
. This way, we're sure to not miss an execution path.
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.
Yes, I changed it and bound the new method to the *Image
type, which should be more clear. 👍
So from my local experiments, if I do:
[
{
"id": "a13e0f4e4ce6ce32820739c1b892a2c24f694dfc676216a9e5f19d0596da6968",
"digest": "sha256:108f68845a70455485fb8677c3db83f596dc05ec257ddb4626254ccbd9a0c686",
"names": [
"localhost/img:v1"
],
"layer": "5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
...
}
]
[
{
"id": "a13e0f4e4ce6ce32820739c1b892a2c24f694dfc676216a9e5f19d0596da6968",
"digest": "sha256:108f68845a70455485fb8677c3db83f596dc05ec257ddb4626254ccbd9a0c686",
"names": [
"localhost/img:v1",
"localhost/img:v2",
"localhost/img:v3"
],
"layer": "5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
...
}
]
[
{
"id": "a13e0f4e4ce6ce32820739c1b892a2c24f694dfc676216a9e5f19d0596da6968",
"digest": "sha256:108f68845a70455485fb8677c3db83f596dc05ec257ddb4626254ccbd9a0c686",
"names": [
"localhost/img:v2",
"localhost/img:v3"
],
"names-history": [
"localhost/img:v1"
],
...
},
{
"id": "12d9c90a46f52a4d6abaf2605fd0bf9a89fe8763e3f13993fb894b739b6c1111",
"digest": "sha256:df4879cb75d87edc08639e0c7252cb70945cd304f6eceba43a2349c93f7777c3",
"names": [
"localhost/img:v1"
],
"layer": "5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
...
}
]
[
{
"id": "a13e0f4e4ce6ce32820739c1b892a2c24f694dfc676216a9e5f19d0596da6968",
"digest": "sha256:108f68845a70455485fb8677c3db83f596dc05ec257ddb4626254ccbd9a0c686",
"names": [
"localhost/img:v3"
],
"names-history": [
"localhost/img:v2",
"localhost/img:v1"
],
...
},
{
"id": "12d9c90a46f52a4d6abaf2605fd0bf9a89fe8763e3f13993fb894b739b6c1111",
"digest": "sha256:df4879cb75d87edc08639e0c7252cb70945cd304f6eceba43a2349c93f7777c3",
"names": [
"localhost/img:v1",
"localhost/img:v2"
],
"layer": "5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
...
}
]
I think we could add dedicated command line options to buildah/podman to interact with old images, for example something like
See my example above, I also thought about adding something like a timestamp to indicate when it has been retagged, but this would clash with the current de-duplication approach. |
Can we first explicitly clarify whether the goal of the PR is intended to mirror existing For the former, I suppose we would get more similar behavior by implementing For the latter, it just seems weird to me to see a $name entry in any form in the output after an explicit rm/untag of $name . (That’s an UI concern not directly impacting the design of the c/storage data, but still.) |
… and we would still need to implement |
I think the major use case is: Displaying the image name to the user if an image has no In CRI-O, we could add these values to the ListImages RPC, whereas in podman we could either add an additional colum to |
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 implementation LGTM.
I’m not quite convinced by the proposed UI, but that’s really not something to be solved here and now.
// NamesHistory is an optional set of Names the image had in the past. The | ||
// contained names are free from any duplicates, whereas the newest entry | ||
// is the first one. | ||
NamesHistory []string `json:"names-history,omitempty"` |
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.
Currently (and especially with the changes what I expect to happen for RepoDigests
), Names
can contain both name:tag and name@digest values. So, NamesHistory
would currently contain both as well. Is that OK?
(Ideally, I’d like be to insist on strongly typed values like reference.NamedTagged
, encoding the semantics in the type system, but with Names []string
that doesn’t seem reasonable right now.)
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.
Currently (and especially with the changes what I expect to happen for
RepoDigests
),Names
can contain both name:tag and name@digest values. So,NamesHistory
would currently contain both as well. Is that OK?
I think so.
(Ideally, I’d like be to insist on strongly typed values like
reference.NamedTagged
, encoding the semantics in the type system, but withNames []string
that doesn’t seem reasonable right now.)
Yeah, we could change both Names
and NamesHistory
to be forcibly valid references, but I wanted to add the change as non-breaking as possible.
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.
Well, the deduplication is really not all that much code; if we need to make it a bit more complex to get the data structure we want, we should just do that. On the one hand, if nothing needs a timestamp now, it seems rather pointless to add them now. On the other hand, if we do end up adding timestamps in the future, it can’t be done within the current (One possible way to defer that decision: make the field private or documented-to-be-private, and add a public getter method; then we can enrich the recorded data without breaking the API.) Up to you, @nalind and others, I really understand neither the UI ambitions nor the API design of c/storage sufficiently. |
@saschagrunert You still interested in this? |
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.
Overall I’m not too enthusiastic about the importance of use case (and the partial overlap with missing RepoDigests
functionality feels vaguely suspect), but I’m completely fine with this existing — up to @nalind.
I got another look at the implementation, though, and the code does not match the documentation AFAICS.
images.go
Outdated
@@ -478,9 +484,14 @@ func (r *imageStore) SetMetadata(id, metadata string) error { | |||
} | |||
|
|||
func (r *imageStore) removeName(image *Image, name string) { | |||
image.addNameToHistory(name) |
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.
removeName
is, AFAICS, only called on a name conflict (e.g. if SetNames
adds another name to an image, and that name has been used by a different image); it is not called on untag (SetNames
removing an existing name).
That’s good enough as far as the original motivation goes:
I think the major use case is: Displaying the image name to the user if an image has no Names any more due to re-tag, point 4
but not consistent with how NamesHistory
is documented:
NamesHistory is an optional set of Names the image had in the past.
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.
Alright, I updated the documentation as suggested.
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 was somewhat expecting an implementation change instead of documenting the behavior, but, sure, this is consistent. Up to @nalind.
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.
Yeah I can also change the implementation to match the previous documentation, this was not clear for me in the first place.
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.
Changed the implementation and added tests on top.
This commit adds a new `NamesHistory` field to the `images.json`, which is basically a deduped list of names the image had in the past. The first entry of the list is the latest history entry. The main use case for this feature is to tell the end-user which names/tags an image had in the past if it does not contain any `names` any more. Detailed use case: 1. Pulling `image:v1` into the local registry: `names: [ "image:v1" ]` 2. Pushing a new image as `image:v1` into the remote registry 3. Pulling `image:v1` again into the local registry: - first image: `names: [ "image:v1" ]` - previous v1 image: `names: [], names-history: [ "image:v1" ]` 4. An consumer of the storage API can now process the image name and still display `image` as REPOSITORY, like: * Before: ``` > podman images REPOSITORY TAG IMAGE ID CREATED SIZE image v1 25b62d1b654a 13 seconds ago 2.07 kB <none> <none> b134eff7b955 17 seconds ago 2.07 kB ``` * After: ``` > podman images REPOSITORY TAG IMAGE ID CREATED SIZE image v1 25b62d1b654a 13 seconds ago 2.07 kB image <none> b134eff7b955 17 seconds ago 2.07 kB ``` 5. Since the `NamesHistory` is a slice we would be able to tell the end-user which names an image ID had before. The change should be backwards compatible with previous versions of containers/storage. Signed-off-by: Sascha Grunert <[email protected]>
LGTM |
Hey, may I ask regarding a new release that I can bring this feature into CRI-O and libpod? |
The last release was just 7 days ago but I think Dan wants throw out some of the recent changes soon. @rhatdan, is anything blocking us from cutting another release? |
I will cut a release. |
This commit adds a new
NamesHistory
field to theimages.json
, whichis basically a deduped list of names the image had in the past. The
first entry of the list is the latest history entry.
The main use case for this feature is to tell the end-user which
names/tags an image had in the past if it does not contain any
names
any more.
Detailed use case:
image:v1
into the local registry:names: [ "image:v1" ]
image:v1
into the remote registryimage:v1
again into the local registry:names: [ "image:v1" ]
names: [], names-history: [ "image:v1" ]
still display
image
as REPOSITORY, like:Before:
NamesHistory
is a slice we would be able to tell theend-user which names an image ID had before.
The change should be backwards compatible with previous versions of
containers/storage.
/cc @mtrmac