apocas / dockerode

Docker + Node = Dockerode (Node.js module for Docker's Remote API)
Apache License 2.0
4.39k stars 464 forks source link

Getting one garbage character from container.exec() #736

Open jamesmurdza opened 1 year ago

jamesmurdza commented 1 year ago

I've written two helper functions using Dockerode. The idea is to run a command synchronously and then return the results as a string.

It works well, except each chunk that is returned by stream.on('data') starts with a garbage character, like "X", "*", "!", etc. I can't figure out why.

This happens for multiple commands, such as "bash" and "cat".

Help is much appreciated!

My code below:

async function waitForStreamEnd(stream: NodeJS.ReadableStream): Promise<void> {
  return new Promise<void>((resolve, reject) => {
    try {
      stream.on('end', async () => {
        resolve();
      });
    } catch (err) {
      reject(err);
    }
  });
}

async function runCommandInContainer(container: Docker.Container, command: string[]): Promise<string> {
  const exec = await container.exec({
    Cmd: command,
    AttachStdout: true,
    AttachStderr: true,
  });
  const stream = await exec.start({ hijack: true, stdin: true });
  let output = "";
  stream.on('data', (data) => {
    output += data;
  });
  await waitForStreamEnd(stream);
  return output;
}
Akimyou commented 1 year ago
const readStream = (stream: stream.Duplex) => {
  let output: string = "";
  return new Promise<string>((resolve, reject) => {
    stream.on("data", (chunk: string) => {
      output += chunk;
    });

    stream.on("end", () => {
     // handle garbage
      resolve(output.trim().split("\n").map(processString).join("\n"));
    });
  });

  function processString(str: string): string {
    const out = Buffer.from(str, "binary");
    if (out.readUInt8(0) === 1) {
      return out.toString("utf8", 8);
    } else {
      return out.toString("utf8", 0);
    }
  }
};

May be this function can help you.

jamesmurdza commented 1 year ago

Interesting, I will try this. Any explanation why this would work?

Fhwang0926 commented 1 year ago

add more comment i also has it issue but i guess it is docker' api problem, is not?

for example, exec with ping

image

i just console.log of exec result

jamesmurdza commented 1 year ago

@Fhwang0926 Were you able to figure out any solution?

ewanmellor commented 1 week ago

When you do not use the tty flag, Docker sends data with the first four bytes set to tell you whether the data is from stdout or stderr, and its length. This is the "garbage" that you're seeing at the start of the line.

See "Stream format" within https://docs.docker.com/reference/api/engine/version/v1.43/#tag/Container/operation/ContainerAttach