How to run a bash command via docker exec using Docker.Dotnet

92 Views Asked by At

I am trying to check if a file exists on a docker container. I am doing this using a docker exec. I can run the command:

docker exec [ContainerName] /bin/bash -c "sudo test -f "/repositories/gubbins/file.txt" && echo "true""

In a bash shell and it will do as I desire.

However when I try to execute this using Docker.DotNet as below then it fails:

using (var tty = await _dockerClient.Exec.StartAndAttachContainerExecAsync(
    (await _dockerClient.Exec.ExecCreateContainerAsync(
        containerName,
        new ContainerExecCreateParameters
        {
            AttachStdin = true,
            AttachStderr = true,
            AttachStdout = true,
            Tty = true,
            Detach = false,
            Privileged = true,
            Cmd = new List<string>
            {
                "/bin/bash",
                "-c",
                "\"sudo test -f \"/repositories/gubbins/file.txt\" && echo \"true\"\"",
            }
        })).ID,
    true))
{
    var (stdOut, stdError) = await tty.ReadOutputToEndAsync(CancellationToken.None);
}

Standard Out is: /bin/bash: sudo test -f /repositories/gubbins/file.txt && echo true: No such file or directory

I have tried many permutations of quotes, double quotes, splitting command up etc but cannot get it to work. The issue appears to be that I am using '&&'. What is the correct way to do this?

1

There are 1 best solutions below

0
mJ222398 On BEST ANSWER

I've managed to achieve what I want by using the IExecOperations.InspectContainerExecAsync method:

var execInstanceId = (await _dockerClient.Exec.ExecCreateContainerAsync(
        containerName,
        new ContainerExecCreateParameters
        {
            AttachStdin = true,
            AttachStderr = true,
            AttachStdout = true,
            Tty = true,
            Detach = false,
            Privileged = true,
            Cmd = new List<string>
            {
                "sudo",
                "test",
                "-f",
                $"{containerFilePath}"
            }
        })).ID;

using (var tty = await _dockerClient.Exec.StartAndAttachContainerExecAsync(execInstanceId, true))
{
    var (stdOut, stdError) = await tty.ReadOutputToEndAsync(CancellationToken.None);
    if (!string.IsNullOrEmpty(stdError))
    {
        throw new TestExecutionMachineException(
            $"Something went wrong while checking if file '{containerFilePath}' exists", stdOut, stdError);
    }

    var execInspectResponse = await _dockerClient.Exec.InspectContainerExecAsync(execInstanceId);

    if (execInspectResponse.ExitCode == 0)
        return true;

    if (execInspectResponse.ExitCode == 1)
        return false;

    throw new TestExecutionMachineException($"Something went wrong while checking if file '{containerFilePath}' exists", stdOut);
}

So we inspect the exec instance and check the exit code. If 0 then the file exists, if 1 it does not, and anything else would be some kind of error.