Skip to content

c8d/list: Fix label (and add label!) filter#45289

Merged
thaJeztah merged 1 commit intomoby:masterfrom
vvoland:c8d-label-filter
Apr 13, 2023
Merged

c8d/list: Fix label (and add label!) filter#45289
thaJeztah merged 1 commit intomoby:masterfrom
vvoland:c8d-label-filter

Conversation

@vvoland
Copy link
Copy Markdown
Contributor

@vvoland vvoland commented Apr 6, 2023

Fixes the label filter which compared labels of the containerd Image object instead of the labels from the image config.
Multi-platform images have multiple configurations - in this case the image will match the filter as long as any of the config's labels match the filter.

I tried to use the containerd filter syntax, but it can't really do the label!=key which filters images that DON'T have the label key. The code is here: #45288 - posting it just for posterity, maybe at some point containerd gets that ability or we contribute it and we'll be able use it instead (if we want).

- What I did

- How I did it

- How to verify it

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
busybox      latest    b5d6fe071263   About an hour ago   2.01MB
ubuntu       20.04     24a0df437301   About an hour ago   26MB
ubuntu       22.04     67211c14fa74   About an hour ago   27.4MB

$ docker inspect busybox -f '{{.Config.Labels}}'
map[]
$ docker inspect ubuntu:22.04 -f '{{.Config.Labels}}'
map[org.opencontainers.image.ref.name:ubuntu org.opencontainers.image.version:22.04]
$ docker inspect ubuntu:20.04 -f '{{.Config.Labels}}'
map[org.opencontainers.image.ref.name:ubuntu org.opencontainers.image.version:20.04]



$ docker images --filter label=org.opencontainers.image.ref.name # images with this label (any value)
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
ubuntu       20.04     24a0df437301   About an hour ago   26MB
ubuntu       22.04     67211c14fa74   About an hour ago   27.4MB

$ docker images --filter label=org.opencontainers.image.ref.name=ubuntu # images with exact value of this label
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
ubuntu       20.04     24a0df437301   About an hour ago   26MB
ubuntu       22.04     67211c14fa74   About an hour ago   27.4MB

$ docker images --filter label=org.opencontainers.image.version=22.04 # images with exact value of this label
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
ubuntu       22.04     67211c14fa74   About an hour ago   27.4MB

$ docker images --filter label!=org.opencontainers.image.version # images without this label
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
busybox      latest    b5d6fe071263   About an hour ago   2.01MB

$ docker images --filter label=org.opencontainers.image.version!=22.04 # images with value other than
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
busybox      latest    b5d6fe071263   About an hour ago   2.01MB
ubuntu       20.04     24a0df437301   About an hour ago   26MB

$ docker images --filter label=org.opencontainers.image.version!=22.04 # images with value other than
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
ubuntu       20.04     24a0df437301   2 hours ago   26MB

$ docker images --filter label!=org.opencontainers.image.version!=22.04 # images with value not other than (aka sceptic's way to check equality)
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
ubuntu       22.04     67211c14fa74   2 hours ago   27.4MB

- Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

@vvoland vvoland added status/2-code-review area/images Image Service containerd-integration Issues and PRs related to containerd integration labels Apr 6, 2023
@vvoland vvoland force-pushed the c8d-label-filter branch from 03feb5b to 688cc12 Compare April 6, 2023 16:40
@vvoland vvoland mentioned this pull request Apr 6, 2023
@vvoland
Copy link
Copy Markdown
Contributor Author

vvoland commented Apr 6, 2023

Hmm, failure unrelated, but didn't see this one failing before:

=== Failed
=== FAIL: amd64.integration-cli TestDockerCLILogsSuite/TestLogsFollowSlowStdoutConsumer (1.63s)
    docker_cli_logs_test.go:258: assertion failed: 139264 (actual int) != 150000 (expected int)
    --- FAIL: TestDockerCLILogsSuite/TestLogsFollowSlowStdoutConsumer (1.63s)

=== FAIL: amd64.integration-cli TestDockerCLILogsSuite (19.22s)

EDIT: Oh, it's actually a known flaky: #41276

@vvoland vvoland added this to the 24.0.0 milestone Apr 6, 2023
//
// containerdListFilters is a slice of filters which should be passed to ImageService.List()
// filterFunc is a function that checks whether given image matches the filters.
// TODO(thaJeztah): reimplement filters using containerd filters: see https://github.com/moby/moby/issues/43845
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.

Is this comment still needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We might not be able to reimplement Config-reading filters with c8d filter right now, but maybe in future we could work out something that would allow us to perform more filtering on the containerd side.
So while the TODO itself is not immediately actionable, it still mentions an existing issue.
But yeah, at least It could be rephrased a bit.

@vvoland vvoland force-pushed the c8d-label-filter branch from 688cc12 to b4d2e56 Compare April 7, 2023 08:58
@vvoland
Copy link
Copy Markdown
Contributor Author

vvoland commented Apr 7, 2023

Rebased on master with #45269 merged.

Comment thread daemon/containerd/handlers.go Outdated
Comment thread daemon/containerd/handlers.go Outdated
Comment thread daemon/containerd/handlers.go Outdated
Comment thread daemon/containerd/handlers.go Outdated
Comment thread daemon/containerd/image_list.go Outdated
Comment on lines +369 to +375
negate := strings.HasSuffix(fltrName, "!")

// If filter value is key!=value then flip the above.
if strings.HasSuffix(k, "!") {
k = strings.TrimSuffix(k, "!")
negate = !negate
}
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.

This is confusing me; are we checking the same thing twice here? (Is this correct?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, consider this:
label!=some.image.label=asdf

fltrName=label!
k=some.image.label
v=asdf

negate := strings.HasSuffix(fltrName, "!") checks if the filter name implies negation.
if strings.HasSuffix(k, "!") { checks if the "operator" is !=

This is a bit awkward, because now we have both label! as a filter (to be backwards compatible with non-c8d Docker) and != as a operator filter expression (to make it consistent with containerd filters, and we probably might want to switch completely to them in future).
So something like this will also work: label!=some.image.label!=asdf (but would be equal to label=some.image.label=asdf).

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.

This is a bit awkward, because now we have both label! as a filter (to be backwards compatible with non-c8d Docker) and != as a operator filter expression

Yeah the label! was one giant hack, but I wondered if we weren't already handling that with the first step (if we see the filter "name" is label! we could trim that, and set the operator to !=.

(I'm rambling; I need to have another look at the code)

So something like this will also work: label!=some.image.label!=asdf (but would be equal to label=some.image.label=asdf).

Did that work before? 🤯 I wonder if we ever designed that, or if it's (like many things with our filtering) just "happened to be there".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Did that work before? 🤯

Yep! (it was available only for image prune though, not image list)

$ docker info -f '{{.Driver}}'
overlay2

$ docker image prune -a --filter 'label!=org.opencontainers.image.version!=22.04'
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
untagged: ubuntu:latest
untagged: ubuntu@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21
deleted: sha256:bab8ce5c00ca3ef91e0d3eb4c6e6d6ec7cffa9574c447fd8d54a8d96e7c1c80e
deleted: sha256:874b048c963ab55b06939c39d59303fb975d323822a4ea48a02ac8dc635ea371

Comment thread daemon/containerd/image_list.go Outdated
Comment thread daemon/containerd/image_list.go Outdated
}
}

return nil, errFoundConfig
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.

Wondering if the reverse would work, and if that would be a more "natural" approach; return an errdefs.NotFound(), and then handle the error like;

		if err != nil {
			if !errdefs.IsNotFound(err) {
				logrus.WithFields(logrus.Fields{
					logrus.ErrorKey: err,
					"image":         image.Name,
					"checks":        checks,
				}).Error("failed to check image labels")
			}
			return false
		}
		return true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nope, we want to exit as soon as we find a matching config from that image - if we already know that this image has a config that matches filters, we don't need to check anything else. Returning an "operation failed successfully" will make the whole Dispatch stop and we'll know it stopped because it found what we were looking for.

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! Gotcha, yes, the error is to make the images.Dispatch cancel (it doesn't if images.HandlerFunc() returns a nil-error)!

Got it now. Perhaps that would warrant a comment either at the return nil, errFoundConfig line, or at the errFoundConfig := errors.New(.... line (or perhaps both); WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added small comments to both.

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! just opened vvoland#5 committing my suggestons; let me know if those look good to you 😂 (classic race condition)

@vvoland vvoland force-pushed the c8d-label-filter branch 2 times, most recently from 9e0fb0c to 8e9f865 Compare April 13, 2023 13:30
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, thanks!

We need to look at these filters in a wider scope; they're quite a bit of a mess (poorly documented, different implementations, some of which as "ever-so-slightly-different"). This one works though, so let's get it in 👍

@thaJeztah
Copy link
Copy Markdown
Member

Interesting (but unrelated) failure on arm64 (hadn't seen that one before; looks like just a random flaky, but posting just in case);

=== FAIL: libnetwork TestDNSProxyServFail (0.08s)
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:206: Try connecting to DNS server ...
    resolver_test.go:279: DNS Server can be reached
time="2023-04-13T13:45:05Z" level=warning msg="[resolver] connect failed" error="dial tcp 127.0.0.1:53: connect: connection refused"
time="2023-04-13T13:45:05Z" level=warning msg="[resolver] connect failed" error="dial tcp 127.0.0.1:53: connect: connection refused"
    resolver_test.go:297: Expected 2 DNS querries. Found: 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/images Image Service containerd-integration Issues and PRs related to containerd integration status/4-merge

Projects

Development

Successfully merging this pull request may close these issues.

3 participants