Skip to content

Commit

Permalink
feature: cri manager could get the log of container
Browse files Browse the repository at this point in the history
Signed-off-by: YaoZengzeng <[email protected]>
  • Loading branch information
YaoZengzeng committed Mar 20, 2018
1 parent fa50191 commit 357d342
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 2 deletions.
111 changes: 111 additions & 0 deletions daemon/containerio/cri_log_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package containerio

import (
"bufio"
"bytes"
"io"
"os"
"time"

"github.com/sirupsen/logrus"
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)

const (
// delimiter used in cri logging format.
delimiter = ' '
// eof is end-of-line.
eol = '\n'
// timestampFormat is the timestamp format used in cri logging format.
timestampFormat = time.RFC3339Nano
// pipeBufSize is the system PIPE_BUF size, on linux it is 4096 bytes.
pipeBufSize = 4096
// bufSize is the size of the read buffer.
bufSize = pipeBufSize - len(timestampFormat) - len(Stdout) - 2 /*2 delimiter*/ - 1 /*eol*/
)

// StreamType is the type of the stream.
type StreamType string

const (
// Stdin stream type.
Stdin StreamType = "stdin"
// Stdout stream type.
Stdout StreamType = "stdout"
// Stderr stream type.
Stderr StreamType = "stderr"
)

func init() {
Register(func() Backend {
return &criLogFile{}
})
}

type criLogFile struct {
file *os.File
pipeWriter *io.PipeWriter
pipeReader *io.PipeReader
closed bool
}

func (c *criLogFile) Name() string {
return "cri-log-file"
}

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)
return nil
}

func redirectLogs(w io.WriteCloser, r io.ReadCloser, stream StreamType) {
defer r.Close()
defer w.Close()
streamBytes := []byte(stream)
delimiterBytes := []byte{delimiter}
partialBytes := []byte(runtime.LogTagPartial)
fullBytes := []byte(runtime.LogTagFull)
br := bufio.NewReaderSize(r, bufSize)
for {
lineBytes, isPrefix, err := br.ReadLine()
if err != nil {
if err == io.EOF {
logrus.Infof("finish redirecting log file")
} else {
logrus.Errorf("failed to redirect log file: %v", err)
}
return
}
tagBytes := fullBytes
if isPrefix {
tagBytes = partialBytes
}
timestampBytes := time.Now().AppendFormat(nil, time.RFC3339Nano)
data := bytes.Join([][]byte{timestampBytes, streamBytes, tagBytes, lineBytes}, delimiterBytes)
data = append(data, eol)
_, err = w.Write(data)
if err != nil {
logrus.Errorf("failed to write %q log to log file: %v", stream, err)
}
}
}

func (c *criLogFile) Out() io.Writer {
return c.pipeWriter
}

func (c *criLogFile) In() io.Reader {
// Log doesn't need stdin.
return nil
}

func (c *criLogFile) Close() error {
if c.closed {
return nil
}
c.closed = true
return c.pipeWriter.Close()
}
13 changes: 13 additions & 0 deletions daemon/containerio/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package containerio
import (
"bytes"
"net/http"
"os"

"github.com/alibaba/pouch/cri/stream/remotecommand"
)
Expand All @@ -17,6 +18,7 @@ type Option struct {
stdinBackend string
memBuffer *bytes.Buffer
streams *remotecommand.Streams
criLogFile *os.File
}

// NewOption creates the Option instance.
Expand Down Expand Up @@ -111,3 +113,14 @@ func WithStdinStream() func(*Option) {
opt.stdinBackend = "streams"
}
}

// WithCriLogFile specified the cri log file backend.
func WithCriLogFile(criLogFile *os.File) func(*Option) {
return func(opt *Option) {
if opt.backends == nil {
opt.backends = make(map[string]struct{})
}
opt.backends["cri-log-file"] = struct{}{}
opt.criLogFile = criLogFile
}
}
8 changes: 8 additions & 0 deletions daemon/mgr/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,10 @@ func (mgr *ContainerManager) openAttachIO(id string, attach *AttachConfig) (*con
options = append(options, containerio.WithStdinStream())
}
}

if attach.CriLogFile != nil {
options = append(options, containerio.WithCriLogFile(attach.CriLogFile))
}
} else {
options = append(options, containerio.WithDiscard())
}
Expand Down Expand Up @@ -928,6 +932,10 @@ func (mgr *ContainerManager) openIO(id string, attach *AttachConfig, exec bool)
options = append(options, containerio.WithStdinStream())
}
}

if attach.CriLogFile != nil {
options = append(options, containerio.WithCriLogFile(attach.CriLogFile))
}
} else if !exec {
options = append(options, containerio.WithRawFile())

Expand Down
4 changes: 4 additions & 0 deletions daemon/mgr/container_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package mgr
import (
"bytes"
"net/http"
"os"
"sync"
"time"

Expand Down Expand Up @@ -55,6 +56,9 @@ type AttachConfig struct {

// Attach using streams.
Streams *remotecommand.Streams

// Attach to the container to get its log.
CriLogFile *os.File
}

// ContainerRemoveOption wraps the container remove interface params.
Expand Down
25 changes: 24 additions & 1 deletion daemon/mgr/cri.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package mgr
import (
"bytes"
"fmt"
"os"
"path/filepath"
"time"

apitypes "github.com/alibaba/pouch/apis/types"
Expand Down Expand Up @@ -389,7 +391,28 @@ func (c *CriManager) CreateContainer(ctx context.Context, r *runtime.CreateConta
return nil, fmt.Errorf("failed to create container for sandbox %q: %v", podSandboxID, err)
}

return &runtime.CreateContainerResponse{ContainerId: createResp.ID}, nil
containerID := createResp.ID

// Get container log.
if config.GetLogPath() != "" {
logPath := filepath.Join(sandboxConfig.GetLogDirectory(), config.GetLogPath())
f, err := os.OpenFile(logPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640)
if err != nil {
return nil, fmt.Errorf("failed to create container for opening log file failed: %v", err)
}
// Attach to the container to get log.
attachConfig := &AttachConfig{
Stdout: true,
Stderr: true,
CriLogFile: f,
}
err = c.ContainerMgr.Attach(context.Background(), containerID, attachConfig)
if err != nil {
return nil, fmt.Errorf("failed to attach to container %q to get its log: %v", containerID, err)
}
}

return &runtime.CreateContainerResponse{ContainerId: containerID}, nil
}

// StartContainer starts the container.
Expand Down
2 changes: 1 addition & 1 deletion hack/cri-test/test-cri.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ 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|Privileged is true|basic operations on container|Runtime info|mount propagation|volume and device|RunAsUser|container port|Streaming|NamespaceOption|SupplementalGroups"}
CRI_FOCUS=${CRI_FOCUS:-"PodSandbox|AppArmor|Privileged is true|Runtime info|Container|RunAsUser|container port|Streaming|NamespaceOption|SupplementalGroups"}

# CRI_SKIP skips the test to skip.
CRI_SKIP=${CRI_SKIP:-"RunAsUserName|HostNetwork"}
Expand Down

0 comments on commit 357d342

Please sign in to comment.