From 27f91f80b9aeeabff4baeb0a08bf7e691799fd53 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Fri, 8 Dec 2017 09:01:34 +0100 Subject: [PATCH] =?UTF-8?q?introduce=20=C2=AB=C2=A0exec=5Fdie=C2=A0=C2=BB?= =?UTF-8?q?=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas De Loof Upstream-commit: aa6bb5cb698ebcf6662e6667bc58055b5b5bde23 Component: engine --- components/engine/api/swagger.yaml | 2 +- components/engine/daemon/exec.go | 15 +++- components/engine/daemon/health.go | 5 +- components/engine/daemon/monitor.go | 5 ++ components/engine/docs/api/version-history.md | 2 + .../engine/integration/system/event_test.go | 74 +++++++++++++++++++ 6 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 components/engine/integration/system/event_test.go diff --git a/components/engine/api/swagger.yaml b/components/engine/api/swagger.yaml index 8c741182ca..32f75d735c 100644 --- a/components/engine/api/swagger.yaml +++ b/components/engine/api/swagger.yaml @@ -6925,7 +6925,7 @@ paths: Various objects within Docker report events when something happens to them. - 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` + 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` Images report these events: `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, and `untag` diff --git a/components/engine/daemon/exec.go b/components/engine/daemon/exec.go index 83b7de2255..65e3204480 100644 --- a/components/engine/daemon/exec.go +++ b/components/engine/daemon/exec.go @@ -138,7 +138,10 @@ func (d *Daemon) ContainerExecCreate(name string, config *types.ExecConfig) (str d.registerExecCommand(cntr, execConfig) - d.LogContainerEvent(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " ")) + attributes := map[string]string{ + "execID": execConfig.ID, + } + d.LogContainerEventWithAttributes(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " "), attributes) return execConfig.ID, nil } @@ -173,7 +176,10 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R c := d.containers.Get(ec.ContainerID) logrus.Debugf("starting exec command %s in container %s", ec.ID, c.ID) - d.LogContainerEvent(c, "exec_start: "+ec.Entrypoint+" "+strings.Join(ec.Args, " ")) + attributes := map[string]string{ + "execID": ec.ID, + } + d.LogContainerEventWithAttributes(c, "exec_start: "+ec.Entrypoint+" "+strings.Join(ec.Args, " "), attributes) defer func() { if err != nil { @@ -269,7 +275,10 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R if _, ok := err.(term.EscapeError); !ok { return errors.Wrap(systemError{err}, "exec attach failed") } - d.LogContainerEvent(c, "exec_detach") + attributes := map[string]string{ + "execID": ec.ID, + } + d.LogContainerEventWithAttributes(c, "exec_detach", attributes) } } return nil diff --git a/components/engine/daemon/health.go b/components/engine/daemon/health.go index 9acf19043b..ff3d54d45d 100644 --- a/components/engine/daemon/health.go +++ b/components/engine/daemon/health.go @@ -89,7 +89,10 @@ func (p *cmdProbe) run(ctx context.Context, d *Daemon, cntr *container.Container execConfig.Env = container.ReplaceOrAppendEnvValues(cntr.CreateDaemonEnvironment(execConfig.Tty, linkedEnv), execConfig.Env) d.registerExecCommand(cntr, execConfig) - d.LogContainerEvent(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " ")) + attributes := map[string]string{ + "execID": execConfig.ID, + } + d.LogContainerEventWithAttributes(cntr, "exec_create: "+execConfig.Entrypoint+" "+strings.Join(execConfig.Args, " "), attributes) output := &limitedBuffer{} err = d.ContainerExecStart(ctx, execConfig.ID, nil, output, output) diff --git a/components/engine/daemon/monitor.go b/components/engine/daemon/monitor.go index dd60239105..6f6928a4d9 100644 --- a/components/engine/daemon/monitor.go +++ b/components/engine/daemon/monitor.go @@ -128,6 +128,11 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc // remove the exec command from the container's store only and not the // daemon's store so that the exec command can be inspected. c.ExecCommands.Delete(execConfig.ID, execConfig.Pid) + attributes := map[string]string{ + "execID": execConfig.ID, + "exitCode": strconv.Itoa(ec), + } + daemon.LogContainerEventWithAttributes(c, "exec_die", attributes) } else { logrus.WithFields(logrus.Fields{ "container": c.ID, diff --git a/components/engine/docs/api/version-history.md b/components/engine/docs/api/version-history.md index 0fdf4648dc..4eca7fbb11 100644 --- a/components/engine/docs/api/version-history.md +++ b/components/engine/docs/api/version-history.md @@ -17,6 +17,8 @@ keywords: "API, Docker, rcli, REST, documentation" [Docker Engine API v1.36](https://docs.docker.com/engine/api/v1.36/) documentation +* `Get /events` now return `exec_die` event when an exec process terminates. + ## v1.35 API changes diff --git a/components/engine/integration/system/event_test.go b/components/engine/integration/system/event_test.go new file mode 100644 index 0000000000..ef7eb1ff5b --- /dev/null +++ b/components/engine/integration/system/event_test.go @@ -0,0 +1,74 @@ +package system + +import ( + "context" + "testing" + + "time" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/strslice" + "github.com/docker/docker/integration/util/request" + "github.com/stretchr/testify/require" +) + +func TestEvents(t *testing.T) { + defer setupTest(t)() + ctx := context.Background() + client := request.NewAPIClient(t) + + container, err := client.ContainerCreate(ctx, + &container.Config{ + Image: "busybox", + Tty: true, + WorkingDir: "/root", + Cmd: strslice.StrSlice([]string{"top"}), + }, + &container.HostConfig{}, + &network.NetworkingConfig{}, + "foo", + ) + require.NoError(t, err) + err = client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}) + require.NoError(t, err) + + id, err := client.ContainerExecCreate(ctx, container.ID, + types.ExecConfig{ + Cmd: strslice.StrSlice([]string{"echo", "hello"}), + }, + ) + require.NoError(t, err) + + filters := filters.NewArgs( + filters.Arg("container", container.ID), + filters.Arg("event", "exec_die"), + ) + msg, errors := client.Events(ctx, types.EventsOptions{ + Filters: filters, + }) + + err = client.ContainerExecStart(ctx, id.ID, + types.ExecStartCheck{ + Detach: true, + Tty: false, + }, + ) + require.NoError(t, err) + + select { + case m := <-msg: + require.Equal(t, m.Type, "container") + require.Equal(t, m.Actor.ID, container.ID) + require.Equal(t, m.Action, "exec_die") + require.Equal(t, m.Actor.Attributes["execID"], id.ID) + require.Equal(t, m.Actor.Attributes["exitCode"], "0") + case err = <-errors: + t.Fatal(err) + case <-time.After(time.Second * 3): + t.Fatal("timeout hit") + } + +}