If we get "container not found" error from containerd, it's possibly
because that this container has already been stopped. It will be ok to
ignore this error and just return an empty stats.
Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
... | ... |
@@ -1165,6 +1165,9 @@ func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { |
1165 | 1165 |
} |
1166 | 1166 |
stats, err := daemon.containerd.Stats(c.ID) |
1167 | 1167 |
if err != nil { |
1168 |
+ if strings.Contains(err.Error(), "container not found") { |
|
1169 |
+ return nil, errNotFound{c.ID} |
|
1170 |
+ } |
|
1168 | 1171 |
return nil, err |
1169 | 1172 |
} |
1170 | 1173 |
s := &types.StatsJSON{} |
... | ... |
@@ -525,6 +525,9 @@ func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { |
525 | 525 |
// Obtain the stats from HCS via libcontainerd |
526 | 526 |
stats, err := daemon.containerd.Stats(c.ID) |
527 | 527 |
if err != nil { |
528 |
+ if strings.Contains(err.Error(), "container not found") { |
|
529 |
+ return nil, errNotFound{c.ID} |
|
530 |
+ } |
|
528 | 531 |
return nil, err |
529 | 532 |
} |
530 | 533 |
|
... | ... |
@@ -39,3 +39,15 @@ func errExecPaused(id string) error { |
39 | 39 |
err := fmt.Errorf("Container %s is paused, unpause the container before exec", id) |
40 | 40 |
return errors.NewRequestConflictError(err) |
41 | 41 |
} |
42 |
+ |
|
43 |
+type errNotFound struct { |
|
44 |
+ containerID string |
|
45 |
+} |
|
46 |
+ |
|
47 |
+func (e errNotFound) Error() string { |
|
48 |
+ return fmt.Sprintf("Container %s is not found", e.containerID) |
|
49 |
+} |
|
50 |
+ |
|
51 |
+func (e errNotFound) ContainerNotFound() bool { |
|
52 |
+ return true |
|
53 |
+} |
... | ... |
@@ -88,24 +88,25 @@ func (s *Collector) Run() { |
88 | 88 |
|
89 | 89 |
for _, pair := range pairs { |
90 | 90 |
stats, err := s.supervisor.GetContainerStats(pair.container) |
91 |
- if err != nil { |
|
92 |
- if _, ok := err.(notRunningErr); !ok { |
|
93 |
- logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err) |
|
94 |
- continue |
|
95 |
- } |
|
96 | 91 |
|
97 |
- // publish empty stats containing only name and ID if not running |
|
92 |
+ switch err.(type) { |
|
93 |
+ case nil: |
|
94 |
+ // FIXME: move to containerd on Linux (not Windows) |
|
95 |
+ stats.CPUStats.SystemUsage = systemUsage |
|
96 |
+ stats.CPUStats.OnlineCPUs = onlineCPUs |
|
97 |
+ |
|
98 |
+ pair.publisher.Publish(*stats) |
|
99 |
+ |
|
100 |
+ case notRunningErr, notFoundErr: |
|
101 |
+ // publish empty stats containing only name and ID if not running or not found |
|
98 | 102 |
pair.publisher.Publish(types.StatsJSON{ |
99 | 103 |
Name: pair.container.Name, |
100 | 104 |
ID: pair.container.ID, |
101 | 105 |
}) |
102 |
- continue |
|
103 |
- } |
|
104 |
- // FIXME: move to containerd on Linux (not Windows) |
|
105 |
- stats.CPUStats.SystemUsage = systemUsage |
|
106 |
- stats.CPUStats.OnlineCPUs = onlineCPUs |
|
107 | 106 |
|
108 |
- pair.publisher.Publish(*stats) |
|
107 |
+ default: |
|
108 |
+ logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err) |
|
109 |
+ } |
|
109 | 110 |
} |
110 | 111 |
} |
111 | 112 |
} |
... | ... |
@@ -114,3 +115,8 @@ type notRunningErr interface { |
114 | 114 |
error |
115 | 115 |
ContainerIsRunning() bool |
116 | 116 |
} |
117 |
+ |
|
118 |
+type notFoundErr interface { |
|
119 |
+ error |
|
120 |
+ ContainerNotFound() bool |
|
121 |
+} |