dotnet / Docker.DotNet

:whale: .NET (C#) Client Library for Docker API
https://www.nuget.org/packages/Docker.DotNet/
MIT License
2.23k stars 381 forks source link

Add support for handling systemerr stream from daemon #680

Open Folleach opened 2 months ago

Folleach commented 2 months ago

Context

In the current version of Docker.DotNet (v3.125.15), there is no support for handling the Systemerr stream when demultiplexing events from Docker.
When docker sends Systemerr, the library throws an IOException with the message "unknown stream type"

Reproduce

To reproduce this issue, we have a valid container f13d4aec

root@domain:~# docker logs f13d4aec
{truncated}
2024-06-27 09:27:37.337196+00:00 [info] <0.683.0>  * rabbitmq_management_agent
2024-06-27 09:27:37.337196+00:00 [info] <0.683.0>  * rabbitmq_web_dispatch
2024-06-27 09:27:37.803052+00:00 [info] <0.9.0> Time to start RabbitMQ: 12848 ms
root@domain:~# echo $?
0

Steps

  1. Break json in logs to simulate a scenario where Docker would send a SystemErr

    echo -e "\n{invalid_json\n" > /var/lib/docker/containers/{containerId}/{containerId}-json.log
  2. Ensure that docker logs command exited with non-zero code

    root@domain:~# docker logs f13d4aec
    error from daemon in stream: Error grabbing logs: invalid character 'i' looking for beginning of object key string
    
    root@domain:~# echo $?
    1
  3. Using the library to view logs

    using Docker.DotNet;
    using Docker.DotNet.Models;
    
    var client = new DockerClientConfiguration(
           new Uri("http://192.168.1.189:2375"))
       .CreateClient();
    
    var response = await client.Containers.GetContainerLogsAsync("f13d4aec", false, new ContainerLogsParameters()
    {
       ShowStdout = true
    });
    
    var (stdout, stderr) = await response.ReadOutputToEndAsync(CancellationToken.None);

    This will throw an exception

    System.IO.IOException: unknown stream type

Changes

Therefore, this PR introduces a new handler for Systemerr stream within Docerk.DotNet.
It reads the message and throws a DockerDaemonException instead of the generic IOException
The message in the exception was completely copied from moby's behavior to provide clear guidance on troubleshooting known issues

Now the exception will look like this

Docker.DotNet.Daemon.DockerDaemonException: error from daemon in stream: Error grabbing logs: invalid character 'i' looking for beginning of object key string
Folleach commented 2 months ago

@dotnet-policy-service agree