Docker stats is not working when a container is using another container's network.
| ... | ... |
@@ -1422,8 +1422,27 @@ func (daemon *Daemon) GetContainerStats(container *container.Container) (*types. |
| 1422 | 1422 |
return stats, nil |
| 1423 | 1423 |
} |
| 1424 | 1424 |
|
| 1425 |
+// Resolve Network SandboxID in case the container reuse another container's network stack |
|
| 1426 |
+func (daemon *Daemon) getNetworkSandboxID(c *container.Container) (string, error) {
|
|
| 1427 |
+ curr := c |
|
| 1428 |
+ for curr.HostConfig.NetworkMode.IsContainer() {
|
|
| 1429 |
+ containerID := curr.HostConfig.NetworkMode.ConnectedContainer() |
|
| 1430 |
+ connected, err := daemon.GetContainer(containerID) |
|
| 1431 |
+ if err != nil {
|
|
| 1432 |
+ return "", fmt.Errorf("Could not get container for %s", containerID)
|
|
| 1433 |
+ } |
|
| 1434 |
+ curr = connected |
|
| 1435 |
+ } |
|
| 1436 |
+ return curr.NetworkSettings.SandboxID, nil |
|
| 1437 |
+} |
|
| 1438 |
+ |
|
| 1425 | 1439 |
func (daemon *Daemon) getNetworkStats(c *container.Container) (map[string]types.NetworkStats, error) {
|
| 1426 |
- sb, err := daemon.netController.SandboxByID(c.NetworkSettings.SandboxID) |
|
| 1440 |
+ sandboxID, err := daemon.getNetworkSandboxID(c) |
|
| 1441 |
+ if err != nil {
|
|
| 1442 |
+ return nil, err |
|
| 1443 |
+ } |
|
| 1444 |
+ |
|
| 1445 |
+ sb, err := daemon.netController.SandboxByID(sandboxID) |
|
| 1427 | 1446 |
if err != nil {
|
| 1428 | 1447 |
return nil, err |
| 1429 | 1448 |
} |
| ... | ... |
@@ -255,3 +255,42 @@ func (s *DockerSuite) TestApiStatsContainerGetMemoryLimit(c *check.C) {
|
| 255 | 255 |
body.Close() |
| 256 | 256 |
c.Assert(fmt.Sprintf("%d", v.MemoryStats.Limit), checker.Equals, fmt.Sprintf("%d", info.MemTotal))
|
| 257 | 257 |
} |
| 258 |
+ |
|
| 259 |
+func (s *DockerSuite) TestApiStatsNoStreamConnectedContainers(c *check.C) {
|
|
| 260 |
+ testRequires(c, DaemonIsLinux) |
|
| 261 |
+ |
|
| 262 |
+ out1, _ := runSleepingContainer(c) |
|
| 263 |
+ id1 := strings.TrimSpace(out1) |
|
| 264 |
+ c.Assert(waitRun(id1), checker.IsNil) |
|
| 265 |
+ |
|
| 266 |
+ out2, _ := runSleepingContainer(c, "--net", "container:"+id1) |
|
| 267 |
+ id2 := strings.TrimSpace(out2) |
|
| 268 |
+ c.Assert(waitRun(id2), checker.IsNil) |
|
| 269 |
+ |
|
| 270 |
+ ch := make(chan error) |
|
| 271 |
+ go func() {
|
|
| 272 |
+ resp, body, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/stats?stream=false", id2), nil, "")
|
|
| 273 |
+ defer body.Close() |
|
| 274 |
+ if err != nil {
|
|
| 275 |
+ ch <- err |
|
| 276 |
+ } |
|
| 277 |
+ if resp.StatusCode != http.StatusOK {
|
|
| 278 |
+ ch <- fmt.Errorf("Invalid StatusCode %v", resp.StatusCode)
|
|
| 279 |
+ } |
|
| 280 |
+ if resp.Header.Get("Content-Type") != "application/json" {
|
|
| 281 |
+ ch <- fmt.Errorf("Invalid 'Content-Type' %v", resp.Header.Get("Content-Type"))
|
|
| 282 |
+ } |
|
| 283 |
+ var v *types.Stats |
|
| 284 |
+ if err := json.NewDecoder(body).Decode(&v); err != nil {
|
|
| 285 |
+ ch <- err |
|
| 286 |
+ } |
|
| 287 |
+ ch <- nil |
|
| 288 |
+ }() |
|
| 289 |
+ |
|
| 290 |
+ select {
|
|
| 291 |
+ case err := <-ch: |
|
| 292 |
+ c.Assert(err, checker.IsNil, check.Commentf("Error in stats remote API: %v", err))
|
|
| 293 |
+ case <-time.After(15 * time.Second): |
|
| 294 |
+ c.Fatalf("Stats did not return after timeout")
|
|
| 295 |
+ } |
|
| 296 |
+} |