diff --git a/daemon/containerio/backend.go b/daemon/containerio/backend.go index e1f18b5a7..f3c2eb477 100644 --- a/daemon/containerio/backend.go +++ b/daemon/containerio/backend.go @@ -14,12 +14,15 @@ type Backend interface { // Init initializes the backend io. Init(opt *Option) error - // Out returns the stdout/stderr. + // Out returns the stdout. Out() io.Writer // In returns the stdin. In() io.Reader + // Err returns the stderr. + Err() io.Writer + // Close closes the io. Close() error } diff --git a/daemon/containerio/container_io.go b/daemon/containerio/container_io.go index fe9b9d29a..9939d1b98 100644 --- a/daemon/containerio/container_io.go +++ b/daemon/containerio/container_io.go @@ -118,7 +118,6 @@ func create(opt *Option, typ stdioType, backends map[string]containerBackend) *C // For backend with stdin, close it if stdin finished. io.converge(b.backend.Name(), opt.id, b.backend.In()) b.backend.Close() - b.ring.Close() }(b) break } @@ -149,16 +148,20 @@ func createBackend(opt *Option) map[string]containerBackend { backends[backend.Name()] = containerBackend{ backend: backend, - ring: ringbuff.New(10), + outRing: ringbuff.New(10), + errRing: ringbuff.New(10), } } - // start to subscribe ring buffer. + // start to subscribe stdout and stderr ring buffer. for _, b := range backends { // the goroutine don't exit forever. go func(b containerBackend) { - subscribe(b.backend.Name(), opt.id, b.ring, b.backend.Out()) + subscribe(b.backend.Name(), opt.id, b.outRing, b.backend.Out()) + }(b) + go func(b containerBackend) { + subscribe(b.backend.Name(), opt.id, b.errRing, b.backend.Err()) }(b) } @@ -208,9 +211,18 @@ func (cio *ContainerIO) Write(data []byte) (int, error) { return len(data), nil } - for _, b := range cio.backends { - if cover := b.ring.Push(data); cover { - logrus.Warnf("cover data, backend: %s, id: %s", b.backend.Name(), cio.id) + switch cio.typ { + case stdout: + for _, b := range cio.backends { + if cover := b.outRing.Push(data); cover { + logrus.Warnf("cover data, backend: %s, id: %s", b.backend.Name(), cio.id) + } + } + case stderr: + for _, b := range cio.backends { + if cover := b.errRing.Push(data); cover { + logrus.Warnf("cover data, backend: %s, id: %s", b.backend.Name(), cio.id) + } } } @@ -223,7 +235,8 @@ func (cio *ContainerIO) Close() error { // we need to close ringbuf before close backend, because close ring will flush // the remain data into backend. name := b.backend.Name() - b.ring.Close() + b.outRing.Close() + b.errRing.Close() b.backend.Close() logrus.Infof("close containerio backend: %s, id: %s", name, cio.id) @@ -235,7 +248,8 @@ func (cio *ContainerIO) Close() error { type containerBackend struct { backend Backend - ring *ringbuff.RingBuff + outRing *ringbuff.RingBuff + errRing *ringbuff.RingBuff } // subscribe be called in a groutine. diff --git a/daemon/containerio/cri_log_file.go b/daemon/containerio/cri_log_file.go index 5b4f8c3c6..caf95108b 100644 --- a/daemon/containerio/cri_log_file.go +++ b/daemon/containerio/cri_log_file.go @@ -43,10 +43,12 @@ func init() { } type criLogFile struct { - file *os.File - pipeWriter *io.PipeWriter - pipeReader *io.PipeReader - closed bool + file *os.File + outPipeWriter *io.PipeWriter + outPipeReader *io.PipeReader + errPipeWriter *io.PipeWriter + errPipeReader *io.PipeReader + closed bool } func (c *criLogFile) Name() string { @@ -55,9 +57,10 @@ func (c *criLogFile) Name() string { func (c *criLogFile) Init(opt *Option) error { c.file = opt.criLogFile - c.pipeReader, c.pipeWriter = io.Pipe() - // TODO: redirect stderr. - go redirectLogs(c.file, c.pipeReader, Stdout) + c.outPipeReader, c.outPipeWriter = io.Pipe() + c.errPipeReader, c.errPipeWriter = io.Pipe() + go redirectLogs(c.file, c.outPipeReader, Stdout) + go redirectLogs(c.file, c.errPipeReader, Stderr) return nil } @@ -86,6 +89,7 @@ func redirectLogs(w io.WriteCloser, r io.ReadCloser, stream StreamType) { timestampBytes := time.Now().AppendFormat(nil, time.RFC3339Nano) data := bytes.Join([][]byte{timestampBytes, streamBytes, tagBytes, lineBytes}, delimiterBytes) data = append(data, eol) + // TODO: maybe lock here? _, err = w.Write(data) if err != nil { logrus.Errorf("failed to write %q log to log file: %v", stream, err) @@ -94,7 +98,11 @@ func redirectLogs(w io.WriteCloser, r io.ReadCloser, stream StreamType) { } func (c *criLogFile) Out() io.Writer { - return c.pipeWriter + return c.outPipeWriter +} + +func (c *criLogFile) Err() io.Writer { + return c.errPipeWriter } func (c *criLogFile) In() io.Reader { @@ -107,5 +115,7 @@ func (c *criLogFile) Close() error { return nil } c.closed = true - return c.pipeWriter.Close() + c.outPipeWriter.Close() + c.errPipeWriter.Close() + return nil } diff --git a/daemon/containerio/discard.go b/daemon/containerio/discard.go index 1917ca016..4102a2326 100644 --- a/daemon/containerio/discard.go +++ b/daemon/containerio/discard.go @@ -24,6 +24,10 @@ func (d *discardIO) Out() io.Writer { return d } +func (d *discardIO) Err() io.Writer { + return d +} + func (d *discardIO) In() io.Reader { return d } diff --git a/daemon/containerio/hijack_conn.go b/daemon/containerio/hijack_conn.go index e5bda93a2..efb0a54ab 100644 --- a/daemon/containerio/hijack_conn.go +++ b/daemon/containerio/hijack_conn.go @@ -56,6 +56,10 @@ func (h *hijackConn) In() io.Reader { return h } +func (h *hijackConn) Err() io.Writer { + return h +} + func (h *hijackConn) Close() error { if h.closed { return nil diff --git a/daemon/containerio/mem_buffer.go b/daemon/containerio/mem_buffer.go index e7f113a2a..aaa4bf99d 100644 --- a/daemon/containerio/mem_buffer.go +++ b/daemon/containerio/mem_buffer.go @@ -32,6 +32,10 @@ func (b *memBuffer) In() io.Reader { return b.buffer } +func (b *memBuffer) Err() io.Writer { + return b.buffer +} + func (b *memBuffer) Close() error { // Don't need to close bytes.Buffer. return nil diff --git a/daemon/containerio/raw_file.go b/daemon/containerio/raw_file.go index a2ff72ab7..1401f1190 100644 --- a/daemon/containerio/raw_file.go +++ b/daemon/containerio/raw_file.go @@ -41,6 +41,10 @@ func (r *rawFile) In() io.Reader { return r.file } +func (r *rawFile) Err() io.Writer { + return r.file +} + func (r *rawFile) Close() error { if r.closed { return nil diff --git a/daemon/containerio/streams.go b/daemon/containerio/streams.go index f4fde6434..43dae8660 100644 --- a/daemon/containerio/streams.go +++ b/daemon/containerio/streams.go @@ -35,6 +35,10 @@ func (s *streamIO) In() io.Reader { return s.streams.StdinStream } +func (s *streamIO) Err() io.Writer { + return s.streams.StderrStream +} + func (s *streamIO) Close() error { if s.closed { return nil diff --git a/daemon/mgr/cri.go b/daemon/mgr/cri.go index e9fe79753..2633fe221 100644 --- a/daemon/mgr/cri.go +++ b/daemon/mgr/cri.go @@ -172,6 +172,13 @@ func (c *CriManager) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox return nil, fmt.Errorf("failed to setup sandbox files: %v", err) } + securityContext := config.GetLinux().GetSecurityContext() + hostNet := securityContext.GetNamespaceOptions().GetHostNetwork() + // If it is in host network, no need to configure the network of sandbox. + if hostNet { + return &runtime.RunPodSandboxResponse{PodSandboxId: id}, nil + } + // Step 4: Setup networking for the sandbox. container, err := c.ContainerMgr.Get(ctx, id) if err != nil { @@ -234,6 +241,8 @@ func (c *CriManager) StopPodSandbox(ctx context.Context, r *runtime.StopPodSandb return nil, fmt.Errorf("failed to parse metadata of sandbox %q from container name: %v", podSandboxID, err) } + // TODO: how to figure out if the network is in host mode? + // Maybe we need to store some configuration of sandbox. err = c.CniMgr.TearDownPodNetwork(&ocicni.PodNetwork{ Name: metadata.GetName(), Namespace: metadata.GetNamespace(), diff --git a/hack/cri-test/test-cri.sh b/hack/cri-test/test-cri.sh index b6ae213f0..e52ac02ad 100755 --- a/hack/cri-test/test-cri.sh +++ b/hack/cri-test/test-cri.sh @@ -23,10 +23,10 @@ POUCH_SOCK="/var/run/pouchcri.sock" # CRI_FOCUS focuses the test to run. # With the CRI manager completes its function, we may need to expand this field. -CRI_FOCUS=${CRI_FOCUS:-"PodSandbox|AppArmor|Runtime info|Container|Networking|Streaming|Security Context"} +CRI_FOCUS=${CRI_FOCUS:-} # CRI_SKIP skips the test to skip. -CRI_SKIP=${CRI_SKIP:-"RunAsUserName|HostNetwork|ReadOnlyRootfs is true|seccomp localhost"} +CRI_SKIP=${CRI_SKIP:-"RunAsUserName|seccomp localhost|SELinux|public image with digest|listImage should get exactly 2 repoTags"} # REPORT_DIR is the the directory to store test logs. REPORT_DIR=${REPORT_DIR:-"/tmp/test-cri"}