This fix tries to address the issue in 25000 where `docker stats`
will not show network stats with `NetworkDisabled=true`.
The `NetworkDisabled=true` could be either invoked through
remote API, or through `docker daemon -b none`.
The issue was that when `NetworkDisabled=true` either by API or
by daemon config, there is no SandboxKey for container so an error
will be returned.
This fix fixes this issue by skipping obtaining SandboxKey if
`NetworkDisabled=true`.
Additional test has bee added to cover the changes.
This fix fixes 25000.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
| ... | ... |
@@ -138,8 +138,10 @@ func (daemon *Daemon) GetContainerStats(container *container.Container) (*types. |
| 138 | 138 |
return nil, err |
| 139 | 139 |
} |
| 140 | 140 |
|
| 141 |
- if stats.Networks, err = daemon.getNetworkStats(container); err != nil {
|
|
| 142 |
- return nil, err |
|
| 141 |
+ if !container.Config.NetworkDisabled {
|
|
| 142 |
+ if stats.Networks, err = daemon.getNetworkStats(container); err != nil {
|
|
| 143 |
+ return nil, err |
|
| 144 |
+ } |
|
| 143 | 145 |
} |
| 144 | 146 |
|
| 145 | 147 |
return stats, nil |
| ... | ... |
@@ -1432,3 +1432,55 @@ func (s *DockerSuite) TestContainerApiDeleteWithEmptyName(c *check.C) {
|
| 1432 | 1432 |
c.Assert(status, checker.Equals, http.StatusBadRequest) |
| 1433 | 1433 |
c.Assert(string(out), checker.Contains, "No container name or ID supplied") |
| 1434 | 1434 |
} |
| 1435 |
+ |
|
| 1436 |
+func (s *DockerSuite) TestContainerApiStatsWithNetworkDisabled(c *check.C) {
|
|
| 1437 |
+ // Problematic on Windows as Windows does not support stats |
|
| 1438 |
+ testRequires(c, DaemonIsLinux) |
|
| 1439 |
+ |
|
| 1440 |
+ name := "testing-network-disabled" |
|
| 1441 |
+ config := map[string]interface{}{
|
|
| 1442 |
+ "Image": "busybox", |
|
| 1443 |
+ "Cmd": []string{"top"},
|
|
| 1444 |
+ "NetworkDisabled": true, |
|
| 1445 |
+ } |
|
| 1446 |
+ |
|
| 1447 |
+ status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
|
|
| 1448 |
+ c.Assert(err, checker.IsNil) |
|
| 1449 |
+ c.Assert(status, checker.Equals, http.StatusCreated) |
|
| 1450 |
+ |
|
| 1451 |
+ status, _, err = sockRequest("POST", "/containers/"+name+"/start", nil)
|
|
| 1452 |
+ c.Assert(err, checker.IsNil) |
|
| 1453 |
+ c.Assert(status, checker.Equals, http.StatusNoContent) |
|
| 1454 |
+ |
|
| 1455 |
+ c.Assert(waitRun(name), check.IsNil) |
|
| 1456 |
+ |
|
| 1457 |
+ type b struct {
|
|
| 1458 |
+ status int |
|
| 1459 |
+ body []byte |
|
| 1460 |
+ err error |
|
| 1461 |
+ } |
|
| 1462 |
+ bc := make(chan b, 1) |
|
| 1463 |
+ go func() {
|
|
| 1464 |
+ status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
|
|
| 1465 |
+ bc <- b{status, body, err}
|
|
| 1466 |
+ }() |
|
| 1467 |
+ |
|
| 1468 |
+ // allow some time to stream the stats from the container |
|
| 1469 |
+ time.Sleep(4 * time.Second) |
|
| 1470 |
+ dockerCmd(c, "rm", "-f", name) |
|
| 1471 |
+ |
|
| 1472 |
+ // collect the results from the stats stream or timeout and fail |
|
| 1473 |
+ // if the stream was not disconnected. |
|
| 1474 |
+ select {
|
|
| 1475 |
+ case <-time.After(2 * time.Second): |
|
| 1476 |
+ c.Fatal("stream was not closed after container was removed")
|
|
| 1477 |
+ case sr := <-bc: |
|
| 1478 |
+ c.Assert(sr.err, checker.IsNil) |
|
| 1479 |
+ c.Assert(sr.status, checker.Equals, http.StatusOK) |
|
| 1480 |
+ |
|
| 1481 |
+ // decode only one object from the stream |
|
| 1482 |
+ var s *types.Stats |
|
| 1483 |
+ dec := json.NewDecoder(bytes.NewBuffer(sr.body)) |
|
| 1484 |
+ c.Assert(dec.Decode(&s), checker.IsNil) |
|
| 1485 |
+ } |
|
| 1486 |
+} |