closes #35702 introduce « exec_die » event
Vincent Demeester authored on 2018/01/20 08:03:50... | ... |
@@ -6944,7 +6944,7 @@ paths: |
6944 | 6944 |
|
6945 | 6945 |
Various objects within Docker report events when something happens to them. |
6946 | 6946 |
|
6947 |
- Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, and `update` |
|
6947 |
+ Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `exec_die`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, and `update` |
|
6948 | 6948 |
|
6949 | 6949 |
Images report these events: `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, and `untag` |
6950 | 6950 |
|
... | ... |
@@ -139,7 +139,10 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str |
139 | 139 |
|
140 | 140 |
d.registerExecCommand(cntr, execConfig) |
141 | 141 |
|
142 |
- d.LogContainerEvent(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " ")) |
|
142 |
+ attributes := map[string]string{ |
|
143 |
+ "execID": execConfig.ID, |
|
144 |
+ } |
|
145 |
+ d.LogContainerEventWithAttributes(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " "), attributes) |
|
143 | 146 |
|
144 | 147 |
return execConfig.ID, nil |
145 | 148 |
} |
... | ... |
@@ -174,7 +177,10 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R |
174 | 174 |
|
175 | 175 |
c := d.containers.Get(ec.ContainerID) |
176 | 176 |
logrus.Debugf("starting exec command %s in container %s", ec.ID, c.ID) |
177 |
- d.LogContainerEvent(c, "exec_start: "+ec.Entrypoint+" "+strings.Join(ec.Args, " ")) |
|
177 |
+ attributes := map[string]string{ |
|
178 |
+ "execID": ec.ID, |
|
179 |
+ } |
|
180 |
+ d.LogContainerEventWithAttributes(c, "exec_start: "+ec.Entrypoint+" "+strings.Join(ec.Args, " "), attributes) |
|
178 | 181 |
|
179 | 182 |
defer func() { |
180 | 183 |
if err != nil { |
... | ... |
@@ -270,7 +276,10 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R |
270 | 270 |
if _, ok := err.(term.EscapeError); !ok { |
271 | 271 |
return errdefs.System(errors.Wrap(err, "exec attach failed")) |
272 | 272 |
} |
273 |
- d.LogContainerEvent(c, "exec_detach") |
|
273 |
+ attributes := map[string]string{ |
|
274 |
+ "execID": ec.ID, |
|
275 |
+ } |
|
276 |
+ d.LogContainerEventWithAttributes(c, "exec_detach", attributes) |
|
274 | 277 |
} |
275 | 278 |
} |
276 | 279 |
return nil |
... | ... |
@@ -89,7 +89,10 @@ func (p *cmdProbe) run(ctx context.Context, d *Daemon, cntr *container.Container |
89 | 89 |
execConfig.Env = container.ReplaceOrAppendEnvValues(cntr.CreateDaemonEnvironment(execConfig.Tty, linkedEnv), execConfig.Env) |
90 | 90 |
|
91 | 91 |
d.registerExecCommand(cntr, execConfig) |
92 |
- d.LogContainerEvent(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " ")) |
|
92 |
+ attributes := map[string]string{ |
|
93 |
+ "execID": execConfig.ID, |
|
94 |
+ } |
|
95 |
+ d.LogContainerEventWithAttributes(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " "), attributes) |
|
93 | 96 |
|
94 | 97 |
output := &limitedBuffer{} |
95 | 98 |
err = d.ContainerExecStart(ctx, execConfig.ID, nil, output, output) |
... | ... |
@@ -128,6 +128,11 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc |
128 | 128 |
// remove the exec command from the container's store only and not the |
129 | 129 |
// daemon's store so that the exec command can be inspected. |
130 | 130 |
c.ExecCommands.Delete(execConfig.ID, execConfig.Pid) |
131 |
+ attributes := map[string]string{ |
|
132 |
+ "execID": execConfig.ID, |
|
133 |
+ "exitCode": strconv.Itoa(ec), |
|
134 |
+ } |
|
135 |
+ daemon.LogContainerEventWithAttributes(c, "exec_die", attributes) |
|
131 | 136 |
} else { |
132 | 137 |
logrus.WithFields(logrus.Fields{ |
133 | 138 |
"container": c.ID, |
... | ... |
@@ -17,6 +17,8 @@ keywords: "API, Docker, rcli, REST, documentation" |
17 | 17 |
|
18 | 18 |
[Docker Engine API v1.36](https://docs.docker.com/engine/api/v1.36/) documentation |
19 | 19 |
|
20 |
+* `Get /events` now return `exec_die` event when an exec process terminates. |
|
21 |
+ |
|
20 | 22 |
|
21 | 23 |
## v1.35 API changes |
22 | 24 |
|
23 | 25 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,74 @@ |
0 |
+package system |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "context" |
|
4 |
+ "testing" |
|
5 |
+ |
|
6 |
+ "time" |
|
7 |
+ |
|
8 |
+ "github.com/docker/docker/api/types" |
|
9 |
+ "github.com/docker/docker/api/types/container" |
|
10 |
+ "github.com/docker/docker/api/types/filters" |
|
11 |
+ "github.com/docker/docker/api/types/network" |
|
12 |
+ "github.com/docker/docker/api/types/strslice" |
|
13 |
+ "github.com/docker/docker/integration/util/request" |
|
14 |
+ "github.com/stretchr/testify/require" |
|
15 |
+) |
|
16 |
+ |
|
17 |
+func TestEvents(t *testing.T) { |
|
18 |
+ defer setupTest(t)() |
|
19 |
+ ctx := context.Background() |
|
20 |
+ client := request.NewAPIClient(t) |
|
21 |
+ |
|
22 |
+ container, err := client.ContainerCreate(ctx, |
|
23 |
+ &container.Config{ |
|
24 |
+ Image: "busybox", |
|
25 |
+ Tty: true, |
|
26 |
+ WorkingDir: "/root", |
|
27 |
+ Cmd: strslice.StrSlice([]string{"top"}), |
|
28 |
+ }, |
|
29 |
+ &container.HostConfig{}, |
|
30 |
+ &network.NetworkingConfig{}, |
|
31 |
+ "foo", |
|
32 |
+ ) |
|
33 |
+ require.NoError(t, err) |
|
34 |
+ err = client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}) |
|
35 |
+ require.NoError(t, err) |
|
36 |
+ |
|
37 |
+ id, err := client.ContainerExecCreate(ctx, container.ID, |
|
38 |
+ types.ExecConfig{ |
|
39 |
+ Cmd: strslice.StrSlice([]string{"echo", "hello"}), |
|
40 |
+ }, |
|
41 |
+ ) |
|
42 |
+ require.NoError(t, err) |
|
43 |
+ |
|
44 |
+ filters := filters.NewArgs( |
|
45 |
+ filters.Arg("container", container.ID), |
|
46 |
+ filters.Arg("event", "exec_die"), |
|
47 |
+ ) |
|
48 |
+ msg, errors := client.Events(ctx, types.EventsOptions{ |
|
49 |
+ Filters: filters, |
|
50 |
+ }) |
|
51 |
+ |
|
52 |
+ err = client.ContainerExecStart(ctx, id.ID, |
|
53 |
+ types.ExecStartCheck{ |
|
54 |
+ Detach: true, |
|
55 |
+ Tty: false, |
|
56 |
+ }, |
|
57 |
+ ) |
|
58 |
+ require.NoError(t, err) |
|
59 |
+ |
|
60 |
+ select { |
|
61 |
+ case m := <-msg: |
|
62 |
+ require.Equal(t, m.Type, "container") |
|
63 |
+ require.Equal(t, m.Actor.ID, container.ID) |
|
64 |
+ require.Equal(t, m.Action, "exec_die") |
|
65 |
+ require.Equal(t, m.Actor.Attributes["execID"], id.ID) |
|
66 |
+ require.Equal(t, m.Actor.Attributes["exitCode"], "0") |
|
67 |
+ case err = <-errors: |
|
68 |
+ t.Fatal(err) |
|
69 |
+ case <-time.After(time.Second * 3): |
|
70 |
+ t.Fatal("timeout hit") |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+} |