mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Update docs + fix endian issue
This commit is contained in:
parent
082d142024
commit
cb18a6e1b9
6 changed files with 63 additions and 95 deletions
|
@ -951,7 +951,7 @@ func TestPostContainersAttach(t *testing.T) {
|
|||
})
|
||||
|
||||
setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
|
||||
if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 6, 0, 0, 0})+"hello", stdout, stdinPipe, 15); err != nil {
|
||||
if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 15); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
@ -1040,7 +1040,7 @@ func TestPostContainersAttachStderr(t *testing.T) {
|
|||
})
|
||||
|
||||
setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
|
||||
if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 6, 0, 0, 0})+"hello", stdout, stdinPipe, 15); err != nil {
|
||||
if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 15); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
:title: Attach stream API
|
||||
:description: API Documentation for the Attach command in Docker
|
||||
:keywords: API, Docker, Attach, Stream, REST, documentation
|
||||
|
||||
=================
|
||||
Docker Attach stream API
|
||||
=================
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
1. Brief introduction
|
||||
=====================
|
||||
|
||||
- This is the Attach stream API for Docker
|
||||
|
||||
2. Format
|
||||
=========
|
||||
|
||||
The attach format is a Header and a Payload (frame).
|
||||
|
||||
2.1 Header
|
||||
^^^^^^^^^^
|
||||
|
||||
The header will contain the information on which stream write
|
||||
the stream (stdout or stderr).
|
||||
It also contain the size of the associated frame encoded on the last 4 bytes (uint32).
|
||||
|
||||
It is encoded on the first 8 bytes like this:
|
||||
header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
|
||||
|
||||
STREAM_TYPE can be:
|
||||
- 0: stdin (will be writen on stdout)
|
||||
- 1: stdout
|
||||
- 2: stderr
|
||||
|
||||
SIZE1, SIZE2, SIZE3, SIZE4 are the 4 bytes of the uint32 size.
|
||||
|
||||
2.1 Payload (frame)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The payload is the raw stream.
|
||||
|
||||
3. Implementation
|
||||
=================
|
||||
|
||||
The simplest way to implement the Attach protocol is the following:
|
||||
|
||||
1) Read 8 bytes
|
||||
2) chose stdout or stderr depending on the first byte
|
||||
3) Extract the frame size from the last 4 byets
|
||||
4) Read the extracted size and output it on the correct output
|
||||
5) Goto 1)
|
|
@ -44,10 +44,10 @@ What's new
|
|||
.. http:post:: /containers/(id)/attach
|
||||
|
||||
**New!** You can now split stderr from stdout. This is done by prefixing
|
||||
a header to each transmition. See :doc:`attach_api_1.6`.
|
||||
a header to each transmition. See :http:post:`/containers/(id)/attach`.
|
||||
The WebSocket attach is unchanged.
|
||||
Note that attach calls on previous API version didn't change. Stdout and
|
||||
stderr are merge.
|
||||
Note that attach calls on the previous API version didn't change. Stdout and
|
||||
stderr are merged.
|
||||
|
||||
|
||||
:doc:`docker_remote_api_v1.5`
|
||||
|
|
|
@ -468,7 +468,7 @@ Attach to a container
|
|||
HTTP/1.1 200 OK
|
||||
Content-Type: application/vnd.docker.raw-stream
|
||||
|
||||
{{ PREFIXED STREAM }} See :doc:`attach_api_1.6`
|
||||
{{ STREAM }}
|
||||
|
||||
:query logs: 1/True/true or 0/False/false, return logs. Default false
|
||||
:query stream: 1/True/true or 0/False/false, return stream. Default false
|
||||
|
@ -480,6 +480,49 @@ Attach to a container
|
|||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
**Stream details**:
|
||||
|
||||
When using the TTY setting is enabled in
|
||||
:http:post:`/containers/create`, the stream is the raw data
|
||||
from the process PTY and client's stdin. When the TTY is
|
||||
disabled, then the stream is multiplexed to separate stdout
|
||||
and stderr.
|
||||
|
||||
The format is a **Header** and a **Payload** (frame).
|
||||
|
||||
**HEADER**
|
||||
|
||||
The header will contain the information on which stream write
|
||||
the stream (stdout or stderr). It also contain the size of
|
||||
the associated frame encoded on the last 4 bytes (uint32).
|
||||
|
||||
It is encoded on the first 8 bytes like this::
|
||||
|
||||
header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
|
||||
|
||||
``STREAM_TYPE`` can be:
|
||||
|
||||
- 0: stdin (will be writen on stdout)
|
||||
- 1: stdout
|
||||
- 2: stderr
|
||||
|
||||
``SIZE1, SIZE2, SIZE3, SIZE4`` are the 4 bytes of the uint32 size encoded as big endian.
|
||||
|
||||
**PAYLOAD**
|
||||
|
||||
The payload is the raw stream.
|
||||
|
||||
**IMPLEMENTATION**
|
||||
|
||||
The simplest way to implement the Attach protocol is the following:
|
||||
|
||||
1) Read 8 bytes
|
||||
2) chose stdout or stderr depending on the first byte
|
||||
3) Extract the frame size from the last 4 byets
|
||||
4) Read the extracted size and output it on the correct output
|
||||
5) Goto 1)
|
||||
|
||||
|
||||
|
||||
Wait a container
|
||||
****************
|
||||
|
|
10
server.go
10
server.go
|
@ -1208,16 +1208,20 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std
|
|||
} else {
|
||||
dec := json.NewDecoder(cLog)
|
||||
for {
|
||||
var l utils.JSONLog
|
||||
if err := dec.Decode(&l); err == io.EOF {
|
||||
l := &utils.JSONLog{}
|
||||
|
||||
if err := dec.Decode(l); err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
utils.Debugf("Error streaming logs: %s", err)
|
||||
break
|
||||
}
|
||||
if (l.Stream == "stdout" && stdout) || (l.Stream == "stderr" && stderr) {
|
||||
if l.Stream == "stdout" && stdout {
|
||||
fmt.Fprintf(outStream, "%s", l.Log)
|
||||
}
|
||||
if l.Stream == "stderr" && stderr {
|
||||
fmt.Fprintf(errStream, "%s", l.Log)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,18 +4,8 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func CheckBigEndian() bool {
|
||||
var x uint32 = 0x01020304
|
||||
|
||||
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const (
|
||||
StdWriterPrefixLen = 8
|
||||
StdWriterFdIndex = 0
|
||||
|
@ -32,16 +22,15 @@ var (
|
|||
|
||||
type StdWriter struct {
|
||||
io.Writer
|
||||
prefix StdType
|
||||
sizeBuf []byte
|
||||
byteOrder binary.ByteOrder
|
||||
prefix StdType
|
||||
sizeBuf []byte
|
||||
}
|
||||
|
||||
func (w *StdWriter) Write(buf []byte) (n int, err error) {
|
||||
if w == nil || w.Writer == nil {
|
||||
return 0, errors.New("Writer not instanciated")
|
||||
}
|
||||
w.byteOrder.PutUint32(w.prefix[4:], uint32(len(buf)))
|
||||
binary.BigEndian.PutUint32(w.prefix[4:], uint32(len(buf)))
|
||||
buf = append(w.prefix[:], buf...)
|
||||
|
||||
n, err = w.Writer.Write(buf)
|
||||
|
@ -55,18 +44,10 @@ func NewStdWriter(w io.Writer, t StdType) *StdWriter {
|
|||
return nil
|
||||
}
|
||||
|
||||
var bo binary.ByteOrder
|
||||
|
||||
if CheckBigEndian() {
|
||||
bo = binary.BigEndian
|
||||
} else {
|
||||
bo = binary.LittleEndian
|
||||
}
|
||||
return &StdWriter{
|
||||
Writer: w,
|
||||
prefix: t,
|
||||
sizeBuf: make([]byte, 4),
|
||||
byteOrder: bo,
|
||||
Writer: w,
|
||||
prefix: t,
|
||||
sizeBuf: make([]byte, 4),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,17 +72,9 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error)
|
|||
nr, nw int
|
||||
er, ew error
|
||||
out io.Writer
|
||||
byteOrder binary.ByteOrder
|
||||
frameSize int
|
||||
)
|
||||
|
||||
// Check the machine's endianness
|
||||
if CheckBigEndian() {
|
||||
byteOrder = binary.BigEndian
|
||||
} else {
|
||||
byteOrder = binary.LittleEndian
|
||||
}
|
||||
|
||||
for {
|
||||
// Make sure we have at least a full header
|
||||
for nr < StdWriterPrefixLen {
|
||||
|
@ -132,7 +105,7 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error)
|
|||
}
|
||||
|
||||
// Retrieve the size of the frame
|
||||
frameSize = int(byteOrder.Uint32(buf[StdWriterSizeIndex : StdWriterSizeIndex+4]))
|
||||
frameSize = int(binary.BigEndian.Uint32(buf[StdWriterSizeIndex : StdWriterSizeIndex+4]))
|
||||
|
||||
// Check if the buffer is big enough to read the frame.
|
||||
// Extend it if necessary.
|
||||
|
|
Loading…
Reference in a new issue