Skip to content

containerd: Image delete fixes and cleanup#46840

Merged
thaJeztah merged 4 commits intomoby:masterfrom
dmcgowan:c8d-rmi-cleanup
Dec 19, 2023
Merged

containerd: Image delete fixes and cleanup#46840
thaJeztah merged 4 commits intomoby:masterfrom
dmcgowan:c8d-rmi-cleanup

Conversation

@dmcgowan
Copy link
Copy Markdown
Member

@dmcgowan dmcgowan commented Nov 22, 2023

Ensure that when removing an image, an image is checked consistently against the images with the same target digest.
Update logic of determining which references are the same to fix failing tests.
Add unit testing around delete.

@dmcgowan dmcgowan marked this pull request as ready for review November 22, 2023 04:46
@vvoland vvoland added status/2-code-review area/images Image Distribution containerd-integration Issues and PRs related to containerd integration labels Nov 22, 2023
@rumpl rumpl closed this Nov 27, 2023
@rumpl rumpl reopened this Nov 27, 2023
Copy link
Copy Markdown
Contributor

@vvoland vvoland left a comment

Choose a reason for hiding this comment

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

Just posting a couple of comments/nits.

@dmcgowan dmcgowan force-pushed the c8d-rmi-cleanup branch 2 times, most recently from 0b9a7f7 to 04526ea Compare November 30, 2023 22:17
@thaJeztah thaJeztah requested review from rumpl and vvoland December 1, 2023 11:55
Copy link
Copy Markdown
Contributor

@vvoland vvoland left a comment

Choose a reason for hiding this comment

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

Looks good overall. Just a few comments/questions from me. Don't think any of those is a blocker though.

Comment on lines +358 to +432
if truncatedID.MatchString(refOrID) {
if d, ok := parsed.(reference.Digested); ok {
if cimg, err := i.images.Get(ctx, d.String()); err == nil {
img = &cimg
dgst = d.Digest()
if cimg.Target.Digest != dgst {
// Ambiguous image reference, use reference name
log.G(ctx).WithField("image", refOrID).WithField("target", cimg.Target.Digest).Warn("digest reference points to image with a different digest")
dgst = cimg.Target.Digest
}
} else if !cerrdefs.IsNotFound(err) {
return nil, nil, convertError(err)
} else {
dgst = d.Digest()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(just a note when reviewing, wasn't sure which cases exactly would hit that path)

For the ^(sha256:)?([a-f0-9]{4,64})$ there are few distinct reference cases (refOrID):

  1. sha256:abcdef7890123456789012345678901234567890123456789012345678901234 (algo prefixed full digest)
  2. sha256:abce (algo prefixed truncated digest)
  3. abcdef7890123456789012345678901234567890123456789012345678901234 (unprefixed full digest)
  4. abce (unprefixed truncated digest)

This is what the reference is resolved to in each case (reference.ParseAnyReference):

  1. docker.io/library/sha256:abcdef7890123456789012345678901234567890123456789012345678901234
    type: reference.taggedReference
  2. docker.io/library/sha256:abce
    type: reference.taggedReference
  3. sha256:abcdef7890123456789012345678901234567890123456789012345678901234
    type: reference.digestReference
  4. docker.io/library/abce
    type: reference.repository

(https://go.dev/play/p/FU-Ysh-I2cI)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

1 Seems a bit surprising. I can add more unit tests around these cases to lessen the surprise.

@vvoland
Copy link
Copy Markdown
Contributor

vvoland commented Dec 1, 2023

Oh, also noticed this breaks the TestRemoveByDigest test.
The thing it checks is that you should be able to delete the image using the named and digested reference (taken from RepoDigests).

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
busybox      latest    3fbc63216742   4 months ago   6.09MB

$ docker inspect busybox -f {{.RepoDigests}}
[busybox@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79]

# This should work
$ docker rmi busybox@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79
Error response from daemon: No such image: busybox@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79

@dmcgowan
Copy link
Copy Markdown
Member Author

dmcgowan commented Dec 6, 2023

@vvoland I'll add more unit tests around that case. I don't think the current tests match all the format of references which get created.

if !cerrdefs.IsNotFound(err) {
return nil, nil, convertError(err)
}
return nil, nil, images.ErrImageDoesNotExist{Ref: parsed}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Related to the remove by repo digest test, this is the case that gets hit. There is currently a unit test that checks for this condition. When a digest is provided we can probably fall back to similar logic as when just a hash is provided. The tricky part is whether to return a matched image or not, since in this case there was no actual matched image and trying to avoid any sort of fuzzy matching with whats in containerd. However I think it makes sense to support the repo@digest case even if it is new functionality and doesn't represent any specific image which has been created.

@dmcgowan dmcgowan force-pushed the c8d-rmi-cleanup branch 2 times, most recently from 82a655e to 3f51b7a Compare December 12, 2023 06:28
@dmcgowan
Copy link
Copy Markdown
Member Author

Updated with functionality to match images by repo + digest on rmi.

@rumpl
Copy link
Copy Markdown
Member

rumpl commented Dec 12, 2023

A lot of tests are failing now in integration-cli with assertion failed: error is not nil: Error response from daemon: No such image: busybox:latest: [d411442a41e1e] failed to download busybox https://github.com/moby/moby/actions/runs/7177758758?pr=46840#summary-19545421070

@dmcgowan
Copy link
Copy Markdown
Member Author

Updated, @rumpl late night commit, I missed the zero case. I added a unit test for that now as well.

Still looking at TestDockerCLIRmiSuite/TestRmiUntagHistoryLayer but that isn't holding this PR back.

Add single resolve function to get a consistent list of images matching
the same digest.

Signed-off-by: Derek McGowan <derek@mcg.dev>
Ensure that when removing an image, an image is checked consistently
against the images with the same target digest. Add unit testing around
delete.

Signed-off-by: Derek McGowan <derek@mcg.dev>
When repo and digest is provided, remove all references within a
repository for the given digest.

Signed-off-by: Derek McGowan <derek@mcg.dev>
@dmcgowan
Copy link
Copy Markdown
Member Author

Updated with comment and added a commit which fixes TestRmiUntagHistoryLayer.

The fix for the untag is to re-add the dangling image before deleting the last tag when there are children and the rmi is not forced. I think this matches the intended logic around dangling image, another label scan right before delete is not optimal but we might be able to address that with switching to gc labels in 2.0.

Signed-off-by: Derek McGowan <derek@mcg.dev>
Copy link
Copy Markdown
Contributor

@vvoland vvoland left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

LGTM

assert.ErrorContains(c, err, "")
assert.Assert(c, strings.Contains(out, cID[:12]))
assert.Assert(c, strings.Contains(out, "(must force)"))
assert.Assert(c, strings.Contains(out, "(must force)") || strings.Contains(out, "(must be forced)"))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

😭 do we know where these originate from, or is one in the CLI and one in the daemon?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Both are in the daemon, it is just one case in the old image code that had the reason hardcoded in as (must force), although both containerd and non-containerd use the reason as must be forced. I could have updated the non-containerd code but seems like it could be considered separately.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh! My search only found one, but perhaps I did it wrong.

Yeah, they were somewhat weird error messages in either case.

Comment on lines +36 to +37
// TODO: Add with target option
err := i.images.Delete(compatcontext.WithoutCancel(ctx), img.Name)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should create a tracking ticket for this

}

func isDanglingImage(image containerdimages.Image) bool {
// TODO: Also check for expired
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto (we should create a tracking ticket for this)

@thaJeztah thaJeztah merged commit 43a82da into moby:master Dec 19, 2023
@thaJeztah thaJeztah added this to the 25.0.0 milestone Dec 19, 2023
@dmcgowan dmcgowan deleted the c8d-rmi-cleanup branch January 8, 2024 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/images Image Distribution containerd-integration Issues and PRs related to containerd integration status/2-code-review

Projects

Development

Successfully merging this pull request may close these issues.

4 participants