closes #35702 introduce « exec_die » event
| ... | ... |
@@ -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 |
+} |