dotnet / Docker.DotNet

:whale: .NET (C#) Client Library for Docker API

Home Page:https://www.nuget.org/packages/Docker.DotNet/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Container filters can't be negated

JonathanBout opened this issue · comments

Output of dotnet --info:

Output
.NET SDK:
 Version:           8.0.202
 Commit:            25674bb2f4
 Workload version:  8.0.200-manifests.fe7a266e

Runtime Environment:
OS Name: Windows
OS Version: 10.0.22631
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\8.0.202\

.NET workloads installed:
[android]
Installation Source: VS 17.10.34607.79, VS 17.9.34701.34
Manifest Version: 34.0.79/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.android\34.0.79\WorkloadManifest.json
Install Type: Msi

[maui-windows]
Installation Source: VS 17.10.34607.79, VS 17.9.34701.34
Manifest Version: 8.0.7/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maui\8.0.7\WorkloadManifest.json
Install Type: Msi

[maccatalyst]
Installation Source: VS 17.10.34607.79, VS 17.9.34701.34
Manifest Version: 17.2.8022/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maccatalyst\17.2.8022\WorkloadManifest.json
Install Type: Msi

[ios]
Installation Source: VS 17.10.34607.79, VS 17.9.34701.34
Manifest Version: 17.2.8022/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.ios\17.2.8022\WorkloadManifest.json
Install Type: Msi

[wasm-tools]
Installation Source: VS 17.9.34701.34
Manifest Version: 8.0.3/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.current\8.0.3\WorkloadManifest.json
Install Type: Msi

Host:
Version: 8.0.3
Architecture: x64
Commit: 9f4b1f5d66

.NET SDKs installed:
8.0.101 [C:\Program Files\dotnet\sdk]
8.0.200 [C:\Program Files\dotnet\sdk]
8.0.202 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 6.0.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 7.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 6.0.28 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 6.0.28 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 7.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
x86 [C:\Program Files (x86)\dotnet]
registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
Not set

global.json file:
Not found

Learn more:
https://aka.ms/dotnet/info

Download .NET:
https://aka.ms/dotnet/download

What version of Docker.DotNet?:

3.125.15

Steps to reproduce the issue:

  1. Create a default client
  2. List the containers and add a filter with false:
var containers = await docker.Containers.ListContainersAsync(new ContainersListParameters
{
    Filters = new Dictionary<string, IDictionary<string, bool>>() { { "status", new Dictionary<string, bool>() { { "exited", false } } } },
    All = true,
    Limit = 20,
});

What actually happened?:
I got a list of all exited containers

What did you expect to happen?:
I get a list of all not exited containers

Additional information:
I use ASP.NET Core with dependency injection. The Docker client is registered as a singleton:

builder.Services
	.AddSingleton<IDockerClient>(dockerConfig.CreateClient());

I am curious and interested in which language feature (syntax sugar) I missed. I am unable to compile your provided example. Can you share the docs for the language feature that introduces the syntax you are using (initializing the dictionary)? My test runs fine:

var containersListParameters = new ContainersListParameters();
containersListParameters.Filters = new Dictionary<string, IDictionary<string, bool>> { { "status", new Dictionary<string, bool> { { "exited", true } } } };

The filter only returns exited containers.

Oh my example indeed doesn't compile 😅 I'll update it.
But it does correctly return all exited containers, yes. But it also returns exited containers when I use { "exited", false }

AFAIK the bool flag does nothing. I have 4 container (3 exited, 1 running). I get the following results, which look Ok:

Returns 4:

var containersListParameters = new ContainersListParameters();
// containersListParameters.Filters = new Dictionary<string, IDictionary<string, bool>> { { "status", new Dictionary<string, bool> { { "exited", true } } } };
containersListParameters.All = true;

Returns 1:

var containersListParameters = new ContainersListParameters();
// containersListParameters.Filters = new Dictionary<string, IDictionary<string, bool>> { { "status", new Dictionary<string, bool> { { "exited", true } } } };
containersListParameters.All = false;

Returns 3:

var containersListParameters = new ContainersListParameters();
containersListParameters.Filters = new Dictionary<string, IDictionary<string, bool>> { { "status", new Dictionary<string, bool> { { "exited", true } } } };
// containersListParameters.All = false;

But why was it added then? It's a bit confusing your 3rd example returns the same as this:

var containersListParameters = new ContainersListParameters();
containersListParameters.Filters = new Dictionary<string, IDictionary<string, bool>> { { "status", new Dictionary<string, bool> { { "exited", false} } } };

your 3rd example returns the same as this

I know, but I do not know why there is the additional bool value, if you look into the Docker Engine API, it says:

Filters to process on the container list, encoded as JSON (a map[string][]string). For example, {"status": ["paused"]} will only return paused containers.

Maybe it was necessary in a previous API version? If you want to know the exact details, you probably need to look at QueryString and its history. I am using this library a lot and never noticed any differences whether true or false is used. And according to the API docs, I do not expect them to be necessary at all. Sorry, I cannot help more.

Does any main developer of this project know what the bool flag is supposed to do in a filter?
It definitely does something with the formatting, see this example:

var images1 = await client.Images.ListImagesAsync(
    new ImagesListParameters()
    {
        Filters = new Dictionary<string, IDictionary<string, bool>>()
        {
            {"dangling", new Dictionary<string, bool>() {{"true", true}}}
        }
    });
// Success

Changing the bool flag to false {"dangling", new Dictionary<string, bool>() {{"true", FALSE}}} resulted in:

Unhandled exception. Docker.DotNet.DockerApiException: Docker API responded with status code=BadRequest, response={"message":"invalid filter 'dangling=[true]'"}

at Docker.DotNet.DockerClient.HandleIfErrorResponseAsync(HttpStatusCode statusCode, HttpResponseMessage response, IEnumerable1 handlers) at Docker.DotNet.DockerClient.MakeRequestAsync(IEnumerable1 errorHandlers, HttpMethod method, String path, IQueryString queryString, IRequestContent body, IDictionary`2 headers, TimeSpan timeout, CancellationToken token)
at Docker.DotNet.ImageOperations.ListImagesAsync(ImagesListParameters parameters, CancellationToken cancellationToken)

The brackets dangling=[true] are added in case the bool is set to false. In case true it is dangling=true.