diff --git a/vendor.conf b/vendor.conf index ef8a045311..12f0d352b6 100644 --- a/vendor.conf +++ b/vendor.conf @@ -107,12 +107,12 @@ google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 github.com/containerd/containerd 3fa104f843ec92328912e042b767d26825f202aa github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6 github.com/containerd/continuity 992a5f112bd2211d0983a1cc8562d2882848f3a3 -github.com/containerd/cgroups 29da22c6171a4316169f9205ab6c49f59b5b852f +github.com/containerd/cgroups c0710c92e8b3a44681d1321dcfd1360fc5c6c089 github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e -github.com/containerd/go-runc ed1cbe1fc31f5fb2359d3a54b6330d1a097858b7 +github.com/containerd/go-runc 4f6e87ae043f859a38255247b49c9abc262d002f github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 github.com/dmcgowan/go-tar go1.10 -github.com/stevvooe/ttrpc 76e68349ad9ab4d03d764c713826d31216715e4f +github.com/stevvooe/ttrpc d4528379866b0ce7e9d71f3eb96f0582fc374577 # cluster github.com/docker/swarmkit 68a376dc30d8c4001767c39456b990dbd821371b diff --git a/vendor/github.com/containerd/cgroups/blkio.go b/vendor/github.com/containerd/cgroups/blkio.go index 078d12b2a4..9b15b8a62f 100644 --- a/vendor/github.com/containerd/cgroups/blkio.go +++ b/vendor/github.com/containerd/cgroups/blkio.go @@ -3,12 +3,12 @@ package cgroups import ( "bufio" "fmt" + "io" "io/ioutil" "os" "path/filepath" "strconv" "strings" - "syscall" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -105,8 +105,13 @@ func (b *blkioController) Stat(path string, stats *Metrics) error { }, ) } + f, err := os.Open("/proc/diskstats") + if err != nil { + return err + } + defer f.Close() - devices, err := getDevices("/dev") + devices, err := getDevices(f) if err != nil { return err } @@ -268,50 +273,32 @@ type deviceKey struct { // getDevices makes a best effort attempt to read all the devices into a map // keyed by major and minor number. Since devices may be mapped multiple times, // we err on taking the first occurrence. -func getDevices(path string) (map[deviceKey]string, error) { - // TODO(stevvooe): We are ignoring lots of errors. It might be kind of - // challenging to debug this if we aren't mapping devices correctly. - // Consider logging these errors. - devices := map[deviceKey]string{} - if err := filepath.Walk(path, func(p string, fi os.FileInfo, err error) error { +func getDevices(r io.Reader) (map[deviceKey]string, error) { + + var ( + s = bufio.NewScanner(r) + devices = make(map[deviceKey]string) + ) + for s.Scan() { + fields := strings.Fields(s.Text()) + major, err := strconv.Atoi(fields[0]) if err != nil { - return err + return nil, err } - switch { - case fi.IsDir(): - switch fi.Name() { - case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts": - return filepath.SkipDir - default: - return nil - } - case fi.Name() == "console": - return nil - default: - if fi.Mode()&os.ModeDevice == 0 { - // skip non-devices - return nil - } - - st, ok := fi.Sys().(*syscall.Stat_t) - if !ok { - return fmt.Errorf("%s: unable to convert to system stat", p) - } - - key := deviceKey{major(st.Rdev), minor(st.Rdev)} - if _, ok := devices[key]; ok { - return nil // skip it if we have already populated the path. - } - - devices[key] = p + minor, err := strconv.Atoi(fields[1]) + if err != nil { + return nil, err } - - return nil - }); err != nil { - return nil, err + key := deviceKey{ + major: uint64(major), + minor: uint64(minor), + } + if _, ok := devices[key]; ok { + continue + } + devices[key] = filepath.Join("/dev", fields[2]) } - - return devices, nil + return devices, s.Err() } func major(devNumber uint64) uint64 { diff --git a/vendor/github.com/containerd/cgroups/errors.go b/vendor/github.com/containerd/cgroups/errors.go index d18b4b1df6..a5824fe23f 100644 --- a/vendor/github.com/containerd/cgroups/errors.go +++ b/vendor/github.com/containerd/cgroups/errors.go @@ -12,7 +12,7 @@ var ( ErrFreezerNotSupported = errors.New("cgroups: freezer cgroup not supported on this system") ErrMemoryNotSupported = errors.New("cgroups: memory cgroup not supported on this system") ErrCgroupDeleted = errors.New("cgroups: cgroup deleted") - ErrNoCgroupMountDestination = errors.New("cgroups: cannot found cgroup mount destination") + ErrNoCgroupMountDestination = errors.New("cgroups: cannot find cgroup mount destination") ) // ErrorHandler is a function that handles and acts on errors diff --git a/vendor/github.com/containerd/go-runc/runc.go b/vendor/github.com/containerd/go-runc/runc.go index c5a66a1990..df76ad77a6 100644 --- a/vendor/github.com/containerd/go-runc/runc.go +++ b/vendor/github.com/containerd/go-runc/runc.go @@ -1,7 +1,6 @@ package runc import ( - "bytes" "context" "encoding/json" "errors" @@ -532,7 +531,9 @@ func (r *Runc) Restore(context context.Context, id, bundle string, opts *Restore // Update updates the current container with the provided resource spec func (r *Runc) Update(context context.Context, id string, resources *specs.LinuxResources) error { - buf := bytes.NewBuffer(nil) + buf := getBuf() + defer putBuf(buf) + if err := json.NewEncoder(buf).Encode(resources); err != nil { return err } @@ -638,11 +639,12 @@ func (r *Runc) runOrError(cmd *exec.Cmd) error { } func cmdOutput(cmd *exec.Cmd, combined bool) ([]byte, error) { - var b bytes.Buffer + b := getBuf() + defer putBuf(b) - cmd.Stdout = &b + cmd.Stdout = b if combined { - cmd.Stderr = &b + cmd.Stderr = b } ec, err := Monitor.Start(cmd) if err != nil { diff --git a/vendor/github.com/containerd/go-runc/utils.go b/vendor/github.com/containerd/go-runc/utils.go index 81fcd3f2d8..8cb241aca7 100644 --- a/vendor/github.com/containerd/go-runc/utils.go +++ b/vendor/github.com/containerd/go-runc/utils.go @@ -1,8 +1,10 @@ package runc import ( + "bytes" "io/ioutil" "strconv" + "sync" "syscall" ) @@ -26,3 +28,18 @@ func exitStatus(status syscall.WaitStatus) int { } return status.ExitStatus() } + +var bytesBufferPool = sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(nil) + }, +} + +func getBuf() *bytes.Buffer { + return bytesBufferPool.Get().(*bytes.Buffer) +} + +func putBuf(b *bytes.Buffer) { + b.Reset() + bytesBufferPool.Put(b) +} diff --git a/vendor/github.com/stevvooe/ttrpc/channel.go b/vendor/github.com/stevvooe/ttrpc/channel.go index 4a33827a43..9493d68624 100644 --- a/vendor/github.com/stevvooe/ttrpc/channel.go +++ b/vendor/github.com/stevvooe/ttrpc/channel.go @@ -5,6 +5,7 @@ import ( "context" "encoding/binary" "io" + "net" "sync" "github.com/pkg/errors" @@ -60,16 +61,18 @@ func writeMessageHeader(w io.Writer, p []byte, mh messageHeader) error { var buffers sync.Pool type channel struct { + conn net.Conn bw *bufio.Writer br *bufio.Reader hrbuf [messageHeaderLength]byte // avoid alloc when reading header hwbuf [messageHeaderLength]byte } -func newChannel(w io.Writer, r io.Reader) *channel { +func newChannel(conn net.Conn) *channel { return &channel{ - bw: bufio.NewWriter(w), - br: bufio.NewReader(r), + conn: conn, + bw: bufio.NewWriter(conn), + br: bufio.NewReader(conn), } } diff --git a/vendor/github.com/stevvooe/ttrpc/client.go b/vendor/github.com/stevvooe/ttrpc/client.go index ca76afe19a..f047181678 100644 --- a/vendor/github.com/stevvooe/ttrpc/client.go +++ b/vendor/github.com/stevvooe/ttrpc/client.go @@ -2,8 +2,12 @@ package ttrpc import ( "context" + "io" "net" + "os" + "strings" "sync" + "syscall" "github.com/containerd/containerd/log" "github.com/gogo/protobuf/proto" @@ -11,6 +15,10 @@ import ( "google.golang.org/grpc/status" ) +// ErrClosed is returned by client methods when the underlying connection is +// closed. +var ErrClosed = errors.New("ttrpc: closed") + type Client struct { codec codec conn net.Conn @@ -19,18 +27,20 @@ type Client struct { closed chan struct{} closeOnce sync.Once + closeFunc func() done chan struct{} err error } func NewClient(conn net.Conn) *Client { c := &Client{ - codec: codec{}, - conn: conn, - channel: newChannel(conn, conn), - calls: make(chan *callRequest), - closed: make(chan struct{}), - done: make(chan struct{}), + codec: codec{}, + conn: conn, + channel: newChannel(conn), + calls: make(chan *callRequest), + closed: make(chan struct{}), + done: make(chan struct{}), + closeFunc: func() {}, } go c.run() @@ -91,7 +101,7 @@ func (c *Client) dispatch(ctx context.Context, req *Request, resp *Response) err select { case err := <-errs: - return err + return filterCloseErr(err) case <-c.done: return c.err } @@ -105,6 +115,11 @@ func (c *Client) Close() error { return nil } +// OnClose allows a close func to be called when the server is closed +func (c *Client) OnClose(closer func()) { + c.closeFunc = closer +} + type message struct { messageHeader p []byte @@ -150,6 +165,7 @@ func (c *Client) run() { defer c.conn.Close() defer close(c.done) + defer c.closeFunc() for { select { @@ -171,7 +187,14 @@ func (c *Client) run() { call.errs <- c.recv(call.resp, msg) delete(waiters, msg.StreamID) case <-shutdown: + if shutdownErr != nil { + shutdownErr = filterCloseErr(shutdownErr) + } else { + shutdownErr = ErrClosed + } + shutdownErr = errors.Wrapf(shutdownErr, "ttrpc: client shutting down") + c.err = shutdownErr for _, waiter := range waiters { waiter.errs <- shutdownErr @@ -179,9 +202,12 @@ func (c *Client) run() { c.Close() return case <-c.closed: + if c.err == nil { + c.err = ErrClosed + } // broadcast the shutdown error to the remaining waiters. for _, waiter := range waiters { - waiter.errs <- shutdownErr + waiter.errs <- c.err } return } @@ -209,3 +235,30 @@ func (c *Client) recv(resp *Response, msg *message) error { defer c.channel.putmbuf(msg.p) return proto.Unmarshal(msg.p, resp) } + +// filterCloseErr rewrites EOF and EPIPE errors to ErrClosed. Use when +// returning from call or handling errors from main read loop. +// +// This purposely ignores errors with a wrapped cause. +func filterCloseErr(err error) error { + if err == nil { + return nil + } + + if err == io.EOF { + return ErrClosed + } + + if strings.Contains(err.Error(), "use of closed network connection") { + return ErrClosed + } + + // if we have an epipe on a write, we cast to errclosed + if oerr, ok := err.(*net.OpError); ok && oerr.Op == "write" { + if serr, ok := oerr.Err.(*os.SyscallError); ok && serr.Err == syscall.EPIPE { + return ErrClosed + } + } + + return err +} diff --git a/vendor/github.com/stevvooe/ttrpc/server.go b/vendor/github.com/stevvooe/ttrpc/server.go index edfca0c52c..fd29b719e4 100644 --- a/vendor/github.com/stevvooe/ttrpc/server.go +++ b/vendor/github.com/stevvooe/ttrpc/server.go @@ -16,7 +16,7 @@ import ( ) var ( - ErrServerClosed = errors.New("ttrpc: server close") + ErrServerClosed = errors.New("ttrpc: server closed") ) type Server struct { @@ -281,7 +281,7 @@ func (c *serverConn) run(sctx context.Context) { ) var ( - ch = newChannel(c.conn, c.conn) + ch = newChannel(c.conn) ctx, cancel = context.WithCancel(sctx) active int state connState = connStateIdle