Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 855a056af7829504ccc310587445c61d62427b51)
... | ... |
@@ -575,7 +575,16 @@ func (s *Server) getContainersStats(version version.Version, w http.ResponseWrit |
575 | 575 |
return fmt.Errorf("Missing parameter") |
576 | 576 |
} |
577 | 577 |
|
578 |
- return s.daemon.ContainerStats(vars["name"], boolValueOrDefault(r, "stream", true), ioutils.NewWriteFlusher(w)) |
|
578 |
+ stream := boolValueOrDefault(r, "stream", true) |
|
579 |
+ var out io.Writer |
|
580 |
+ if !stream { |
|
581 |
+ w.Header().Set("Content-Type", "application/json") |
|
582 |
+ out = w |
|
583 |
+ } else { |
|
584 |
+ out = ioutils.NewWriteFlusher(w) |
|
585 |
+ } |
|
586 |
+ |
|
587 |
+ return s.daemon.ContainerStats(vars["name"], stream, out) |
|
579 | 588 |
} |
580 | 589 |
|
581 | 590 |
func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error { |
... | ... |
@@ -15,31 +15,39 @@ func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) er |
15 | 15 |
if err != nil { |
16 | 16 |
return err |
17 | 17 |
} |
18 |
- var pre_cpu_stats types.CpuStats |
|
19 |
- for first_v := range updates { |
|
20 |
- first_update := first_v.(*execdriver.ResourceStats) |
|
21 |
- first_stats := convertToAPITypes(first_update.Stats) |
|
22 |
- pre_cpu_stats = first_stats.CpuStats |
|
23 |
- pre_cpu_stats.SystemUsage = first_update.SystemUsage |
|
24 |
- break |
|
25 |
- } |
|
26 |
- enc := json.NewEncoder(out) |
|
27 |
- for v := range updates { |
|
18 |
+ |
|
19 |
+ var preCpuStats types.CpuStats |
|
20 |
+ getStat := func(v interface{}) *types.Stats { |
|
28 | 21 |
update := v.(*execdriver.ResourceStats) |
29 | 22 |
ss := convertToAPITypes(update.Stats) |
30 |
- ss.PreCpuStats = pre_cpu_stats |
|
23 |
+ ss.PreCpuStats = preCpuStats |
|
31 | 24 |
ss.MemoryStats.Limit = uint64(update.MemoryLimit) |
32 | 25 |
ss.Read = update.Read |
33 | 26 |
ss.CpuStats.SystemUsage = update.SystemUsage |
34 |
- pre_cpu_stats = ss.CpuStats |
|
35 |
- if err := enc.Encode(ss); err != nil { |
|
27 |
+ preCpuStats = ss.CpuStats |
|
28 |
+ return ss |
|
29 |
+ } |
|
30 |
+ |
|
31 |
+ enc := json.NewEncoder(out) |
|
32 |
+ |
|
33 |
+ if !stream { |
|
34 |
+ // prime the cpu stats so they aren't 0 in the final output |
|
35 |
+ s := getStat(<-updates) |
|
36 |
+ |
|
37 |
+ // now pull stats again with the cpu stats primed |
|
38 |
+ s = getStat(<-updates) |
|
39 |
+ err := enc.Encode(s) |
|
40 |
+ daemon.UnsubscribeToContainerStats(name, updates) |
|
41 |
+ return err |
|
42 |
+ } |
|
43 |
+ |
|
44 |
+ for v := range updates { |
|
45 |
+ s := getStat(v) |
|
46 |
+ if err := enc.Encode(s); err != nil { |
|
36 | 47 |
// TODO: handle the specific broken pipe |
37 | 48 |
daemon.UnsubscribeToContainerStats(name, updates) |
38 | 49 |
return err |
39 | 50 |
} |
40 |
- if !stream { |
|
41 |
- break |
|
42 |
- } |
|
43 | 51 |
} |
44 | 52 |
return nil |
45 | 53 |
} |
46 | 54 |
deleted file mode 100644 |
... | ... |
@@ -1,48 +0,0 @@ |
1 |
-package main |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "encoding/json" |
|
5 |
- "fmt" |
|
6 |
- "github.com/docker/docker/api/types" |
|
7 |
- "github.com/go-check/check" |
|
8 |
- "strings" |
|
9 |
- "time" |
|
10 |
-) |
|
11 |
- |
|
12 |
-func (s *DockerSuite) TestCliStatsNoStreamGetCpu(c *check.C) { |
|
13 |
- out, _ := dockerCmd(c, "run", "-d", "--cpu-quota=2000", "busybox", "/bin/sh", "-c", "while true;do echo 'Hello';done") |
|
14 |
- |
|
15 |
- id := strings.TrimSpace(out) |
|
16 |
- if err := waitRun(id); err != nil { |
|
17 |
- c.Fatal(err) |
|
18 |
- } |
|
19 |
- ch := make(chan error) |
|
20 |
- var v *types.Stats |
|
21 |
- go func() { |
|
22 |
- _, body, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/stats?stream=1", id), nil, "") |
|
23 |
- if err != nil { |
|
24 |
- ch <- err |
|
25 |
- } |
|
26 |
- dec := json.NewDecoder(body) |
|
27 |
- if err := dec.Decode(&v); err != nil { |
|
28 |
- ch <- err |
|
29 |
- } |
|
30 |
- ch <- nil |
|
31 |
- }() |
|
32 |
- select { |
|
33 |
- case e := <-ch: |
|
34 |
- if e == nil { |
|
35 |
- var cpuPercent = 0.0 |
|
36 |
- cpuDelta := float64(v.CpuStats.CpuUsage.TotalUsage - v.PreCpuStats.CpuUsage.TotalUsage) |
|
37 |
- systemDelta := float64(v.CpuStats.SystemUsage - v.PreCpuStats.SystemUsage) |
|
38 |
- cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0 |
|
39 |
- if cpuPercent < 1.8 || cpuPercent > 2.2 { |
|
40 |
- c.Fatal("docker stats with no-stream get cpu usage failed") |
|
41 |
- } |
|
42 |
- |
|
43 |
- } |
|
44 |
- case <-time.After(4 * time.Second): |
|
45 |
- c.Fatal("docker stats with no-stream timeout") |
|
46 |
- } |
|
47 |
- |
|
48 |
-} |
49 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,35 @@ |
0 |
+package main |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "encoding/json" |
|
4 |
+ "fmt" |
|
5 |
+ "strings" |
|
6 |
+ |
|
7 |
+ "github.com/docker/docker/api/types" |
|
8 |
+ "github.com/go-check/check" |
|
9 |
+) |
|
10 |
+ |
|
11 |
+func (s *DockerSuite) TestCliStatsNoStreamGetCpu(c *check.C) { |
|
12 |
+ out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true;do echo 'Hello'; usleep 100000; done") |
|
13 |
+ |
|
14 |
+ id := strings.TrimSpace(out) |
|
15 |
+ err := waitRun(id) |
|
16 |
+ c.Assert(err, check.IsNil) |
|
17 |
+ |
|
18 |
+ resp, body, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/stats?stream=false", id), nil, "") |
|
19 |
+ c.Assert(err, check.IsNil) |
|
20 |
+ c.Assert(resp.ContentLength > 0, check.Equals, true, check.Commentf("should not use chunked encoding")) |
|
21 |
+ c.Assert(resp.Header.Get("Content-Type"), check.Equals, "application/json") |
|
22 |
+ |
|
23 |
+ var v *types.Stats |
|
24 |
+ err = json.NewDecoder(body).Decode(&v) |
|
25 |
+ c.Assert(err, check.IsNil) |
|
26 |
+ |
|
27 |
+ var cpuPercent = 0.0 |
|
28 |
+ cpuDelta := float64(v.CpuStats.CpuUsage.TotalUsage - v.PreCpuStats.CpuUsage.TotalUsage) |
|
29 |
+ systemDelta := float64(v.CpuStats.SystemUsage - v.PreCpuStats.SystemUsage) |
|
30 |
+ cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0 |
|
31 |
+ if cpuPercent == 0 { |
|
32 |
+ c.Fatalf("docker stats with no-stream get cpu usage failed: was %v", cpuPercent) |
|
33 |
+ } |
|
34 |
+} |