Do not remove containers from stats list on err

Before this patch, containers are silently removed from the stats list
on error. This patch instead will display `--` for all fields for the
container that had the error, allowing it to recover from errors.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff 2016-03-01 17:10:13 -05:00
Родитель 7268eb97bc
Коммит ff08036cc0
4 изменённых файлов: 26 добавлений и 23 удалений

Просмотреть файл

@ -10,6 +10,7 @@ import (
"golang.org/x/net/context"
"github.com/Sirupsen/logrus"
Cli "github.com/docker/docker/cli"
"github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/events"
@ -169,20 +170,12 @@ func (cli *DockerCli) CmdStats(args ...string) error {
for range time.Tick(500 * time.Millisecond) {
printHeader()
toRemove := []int{}
cStats.mu.Lock()
for i, s := range cStats.cs {
for _, s := range cStats.cs {
if err := s.Display(w); err != nil && !*noStream {
toRemove = append(toRemove, i)
logrus.Debugf("stats: got error for %s: %v", s.Name, err)
}
}
for j := len(toRemove) - 1; j >= 0; j-- {
i := toRemove[j]
cStats.cs = append(cStats.cs[:i], cStats.cs[i+1:]...)
}
if len(cStats.cs) == 0 && !showAll {
return nil
}
cStats.mu.Unlock()
w.Flush()
if *noStream {

Просмотреть файл

@ -2,12 +2,14 @@ package client
import (
"encoding/json"
"errors"
"fmt"
"io"
"strings"
"sync"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/engine-api/client"
"github.com/docker/engine-api/types"
"github.com/docker/go-units"
@ -25,7 +27,7 @@ type containerStats struct {
BlockRead float64
BlockWrite float64
PidsCurrent uint64
mu sync.RWMutex
mu sync.Mutex
err error
}
@ -62,6 +64,7 @@ func (s *stats) isKnownContainer(cid string) (int, bool) {
}
func (s *containerStats) Collect(cli client.APIClient, streamStats bool, waitFirst *sync.WaitGroup) {
logrus.Debugf("collecting stats for %s", s.Name)
var (
getFirst bool
previousCPU uint64
@ -90,9 +93,11 @@ func (s *containerStats) Collect(cli client.APIClient, streamStats bool, waitFir
go func() {
for {
var v *types.StatsJSON
if err := dec.Decode(&v); err != nil {
dec = json.NewDecoder(io.MultiReader(dec.Buffered(), responseBody))
u <- err
return
continue
}
var memPercent = 0.0
@ -139,6 +144,7 @@ func (s *containerStats) Collect(cli client.APIClient, streamStats bool, waitFir
s.BlockRead = 0
s.BlockWrite = 0
s.PidsCurrent = 0
s.err = errors.New("timeout waiting for stats")
s.mu.Unlock()
// if this is the first stat you get, release WaitGroup
if !getFirst {
@ -150,8 +156,9 @@ func (s *containerStats) Collect(cli client.APIClient, streamStats bool, waitFir
s.mu.Lock()
s.err = err
s.mu.Unlock()
return
continue
}
s.err = nil
// if this is the first stat you get, release WaitGroup
if !getFirst {
getFirst = true
@ -165,12 +172,20 @@ func (s *containerStats) Collect(cli client.APIClient, streamStats bool, waitFir
}
func (s *containerStats) Display(w io.Writer) error {
s.mu.RLock()
defer s.mu.RUnlock()
s.mu.Lock()
defer s.mu.Unlock()
// NOTE: if you change this format, you must also change the err format below!
format := "%s\t%.2f%%\t%s / %s\t%.2f%%\t%s / %s\t%s / %s\t%d\n"
if s.err != nil {
return s.err
format = "%s\t%s\t%s / %s\t%s\t%s / %s\t%s / %s\t%s\n"
errStr := "--"
fmt.Fprintf(w, format,
s.Name, errStr, errStr, errStr, errStr, errStr, errStr, errStr, errStr, errStr,
)
err := s.err
return err
}
fmt.Fprintf(w, "%s\t%.2f%%\t%s / %s\t%.2f%%\t%s / %s\t%s / %s\t%d\n",
fmt.Fprintf(w, format,
s.Name,
s.CPUPercentage,
units.BytesSize(s.Memory), units.BytesSize(s.MemoryLimit),

Просмотреть файл

@ -2,7 +2,6 @@ package client
import (
"bytes"
"sync"
"testing"
"github.com/docker/engine-api/types"
@ -20,7 +19,6 @@ func TestDisplay(t *testing.T) {
BlockRead: 100 * 1024 * 1024,
BlockWrite: 800 * 1024 * 1024,
PidsCurrent: 1,
mu: sync.RWMutex{},
}
var b bytes.Buffer
if err := c.Display(&b); err != nil {

Просмотреть файл

@ -120,10 +120,7 @@ func (s *DockerSuite) TestStatsAllNoStream(c *check.C) {
func (s *DockerSuite) TestStatsAllNewContainersAdded(c *check.C) {
// Windows does not support stats
// TODO: remove SameHostDaemon
// The reason it was added is because, there seems to be some race that makes this test fail
// for remote daemons (namely in the win2lin CI). We highly welcome contributions to fix this.
testRequires(c, DaemonIsLinux, SameHostDaemon)
testRequires(c, DaemonIsLinux)
id := make(chan string)
addedChan := make(chan struct{})