github.com/moby/docker@v26.1.3+incompatible/integration-cli/docker_cli_events_test.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io" 9 "os" 10 "os/exec" 11 "strconv" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/docker/docker/api/types/container" 17 eventtypes "github.com/docker/docker/api/types/events" 18 "github.com/docker/docker/client" 19 eventstestutils "github.com/docker/docker/daemon/events/testutils" 20 "github.com/docker/docker/integration-cli/cli" 21 "github.com/docker/docker/integration-cli/cli/build" 22 "github.com/docker/docker/testutil" 23 "gotest.tools/v3/assert" 24 is "gotest.tools/v3/assert/cmp" 25 "gotest.tools/v3/icmd" 26 ) 27 28 type DockerCLIEventSuite struct { 29 ds *DockerSuite 30 } 31 32 func (s *DockerCLIEventSuite) TearDownTest(ctx context.Context, c *testing.T) { 33 s.ds.TearDownTest(ctx, c) 34 } 35 36 func (s *DockerCLIEventSuite) OnTimeout(c *testing.T) { 37 s.ds.OnTimeout(c) 38 } 39 40 func (s *DockerCLIEventSuite) TestEventsTimestampFormats(c *testing.T) { 41 name := "events-time-format-test" 42 43 // Start stopwatch, generate an event 44 start := daemonTime(c) 45 time.Sleep(1100 * time.Millisecond) // so that first event occur in different second from since (just for the case) 46 cli.DockerCmd(c, "run", "--rm", "--name", name, "busybox", "true") 47 time.Sleep(1100 * time.Millisecond) // so that until > since 48 end := daemonTime(c) 49 50 // List of available time formats to --since 51 unixTs := func(t time.Time) string { return fmt.Sprintf("%v", t.Unix()) } 52 rfc3339 := func(t time.Time) string { return t.Format(time.RFC3339) } 53 duration := func(t time.Time) string { return time.Since(t).String() } 54 55 // --since=$start must contain only the 'untag' event 56 for _, f := range []func(time.Time) string{unixTs, rfc3339, duration} { 57 since, until := f(start), f(end) 58 out := cli.DockerCmd(c, "events", "--since="+since, "--until="+until).Stdout() 59 events := strings.Split(out, "\n") 60 events = events[:len(events)-1] 61 62 nEvents := len(events) 63 assert.Assert(c, nEvents >= 5) 64 containerEvents := eventActionsByIDAndType(c, events, name, "container") 65 assert.Assert(c, is.DeepEqual(containerEvents, []string{"create", "attach", "start", "die", "destroy"}), out) 66 } 67 } 68 69 func (s *DockerCLIEventSuite) TestEventsUntag(c *testing.T) { 70 const imgName = "busybox" 71 cli.DockerCmd(c, "tag", imgName, "utest:tag1") 72 cli.DockerCmd(c, "tag", imgName, "utest:tag2") 73 cli.DockerCmd(c, "rmi", "utest:tag1") 74 cli.DockerCmd(c, "rmi", "utest:tag2") 75 76 result := icmd.RunCmd(icmd.Cmd{ 77 Command: []string{dockerBinary, "events", "--since=1"}, 78 Timeout: time.Millisecond * 2500, 79 }) 80 result.Assert(c, icmd.Expected{Timeout: true}) 81 82 events := strings.Split(result.Stdout(), "\n") 83 nEvents := len(events) 84 // The last element after the split above will be an empty string, so we 85 // get the two elements before the last, which are the untags we're 86 // looking for. 87 for _, v := range events[nEvents-3 : nEvents-1] { 88 assert.Check(c, strings.Contains(v, "untag"), "event should be untag") 89 } 90 } 91 92 func (s *DockerCLIEventSuite) TestEventsContainerEvents(c *testing.T) { 93 cli.DockerCmd(c, "run", "--rm", "--name", "container-events-test", "busybox", "true") 94 95 out := cli.DockerCmd(c, "events", "--until", daemonUnixTime(c)).Stdout() 96 events := strings.Split(out, "\n") 97 events = events[:len(events)-1] 98 99 containerEvents := eventActionsByIDAndType(c, events, "container-events-test", "container") 100 if len(containerEvents) > 5 { 101 containerEvents = containerEvents[:5] 102 } 103 assert.Assert(c, is.DeepEqual(containerEvents, []string{"create", "attach", "start", "die", "destroy"}), out) 104 } 105 106 func (s *DockerCLIEventSuite) TestEventsContainerEventsAttrSort(c *testing.T) { 107 since := daemonUnixTime(c) 108 cli.DockerCmd(c, "run", "--rm", "--name", "container-events-test", "busybox", "true") 109 110 out := cli.DockerCmd(c, "events", "--filter", "container=container-events-test", "--since", since, "--until", daemonUnixTime(c)).Stdout() 111 events := strings.Split(out, "\n") 112 113 nEvents := len(events) 114 assert.Assert(c, nEvents >= 3) 115 matchedEvents := 0 116 for _, event := range events { 117 matches := eventstestutils.ScanMap(event) 118 if matches["eventType"] == "container" && matches["action"] == "create" { 119 matchedEvents++ 120 assert.Check(c, strings.Contains(out, "(image=busybox, name=container-events-test)"), "Event attributes not sorted") 121 } else if matches["eventType"] == "container" && matches["action"] == "start" { 122 matchedEvents++ 123 assert.Check(c, strings.Contains(out, "(image=busybox, name=container-events-test)"), "Event attributes not sorted") 124 } 125 } 126 assert.Equal(c, matchedEvents, 2, "missing events for container container-events-test:\n%s", out) 127 } 128 129 func (s *DockerCLIEventSuite) TestEventsContainerEventsSinceUnixEpoch(c *testing.T) { 130 cli.DockerCmd(c, "run", "--rm", "--name", "since-epoch-test", "busybox", "true") 131 timeBeginning := time.Unix(0, 0).Format(time.RFC3339Nano) 132 timeBeginning = strings.ReplaceAll(timeBeginning, "Z", ".000000000Z") 133 out := cli.DockerCmd(c, "events", "--since", timeBeginning, "--until", daemonUnixTime(c)).Stdout() 134 events := strings.Split(out, "\n") 135 events = events[:len(events)-1] 136 137 nEvents := len(events) 138 assert.Assert(c, nEvents >= 5) 139 containerEvents := eventActionsByIDAndType(c, events, "since-epoch-test", "container") 140 assert.Assert(c, is.DeepEqual(containerEvents, []string{"create", "attach", "start", "die", "destroy"}), out) 141 } 142 143 func (s *DockerCLIEventSuite) TestEventsImageTag(c *testing.T) { 144 time.Sleep(1 * time.Second) // because API has seconds granularity 145 since := daemonUnixTime(c) 146 const imgName = "testimageevents:tag" 147 cli.DockerCmd(c, "tag", "busybox", imgName) 148 149 out := cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c)).Stdout() 150 151 events := strings.Split(strings.TrimSpace(out), "\n") 152 assert.Equal(c, len(events), 1, "was expecting 1 event. out=%s", out) 153 event := strings.TrimSpace(events[0]) 154 155 matches := eventstestutils.ScanMap(event) 156 assert.Assert(c, matchEventID(matches, imgName), "matches: %v\nout:\n%s", matches, out) 157 assert.Equal(c, matches["action"], "tag") 158 } 159 160 func (s *DockerCLIEventSuite) TestEventsImagePull(c *testing.T) { 161 // TODO Windows: Enable this test once pull and reliable image names are available 162 testRequires(c, DaemonIsLinux) 163 since := daemonUnixTime(c) 164 testRequires(c, Network) 165 166 cli.DockerCmd(c, "pull", "hello-world") 167 168 out := cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c)).Stdout() 169 events := strings.Split(strings.TrimSpace(out), "\n") 170 event := strings.TrimSpace(events[len(events)-1]) 171 matches := eventstestutils.ScanMap(event) 172 assert.Equal(c, matches["id"], "hello-world:latest") 173 assert.Equal(c, matches["action"], "pull") 174 } 175 176 func (s *DockerCLIEventSuite) TestEventsImageImport(c *testing.T) { 177 // TODO Windows CI. This should be portable once export/import are 178 // more reliable (@swernli) 179 testRequires(c, DaemonIsLinux) 180 181 out := cli.DockerCmd(c, "run", "-d", "busybox", "true").Stdout() 182 cleanedContainerID := strings.TrimSpace(out) 183 184 since := daemonUnixTime(c) 185 out, err := RunCommandPipelineWithOutput( 186 exec.Command(dockerBinary, "export", cleanedContainerID), 187 exec.Command(dockerBinary, "import", "-"), 188 ) 189 assert.NilError(c, err, "import failed with output: %q", out) 190 imageRef := strings.TrimSpace(out) 191 192 out = cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=import").Stdout() 193 events := strings.Split(strings.TrimSpace(out), "\n") 194 assert.Equal(c, len(events), 1) 195 matches := eventstestutils.ScanMap(events[0]) 196 assert.Equal(c, matches["id"], imageRef, "matches: %v\nout:\n%s\n", matches, out) 197 assert.Equal(c, matches["action"], "import", "matches: %v\nout:\n%s\n", matches, out) 198 } 199 200 func (s *DockerCLIEventSuite) TestEventsImageLoad(c *testing.T) { 201 testRequires(c, DaemonIsLinux) 202 myImageName := "footest:v1" 203 cli.DockerCmd(c, "tag", "busybox", myImageName) 204 since := daemonUnixTime(c) 205 206 out := cli.DockerCmd(c, "images", "-q", "--no-trunc", myImageName).Stdout() 207 longImageID := strings.TrimSpace(out) 208 assert.Assert(c, longImageID != "", "Id should not be empty") 209 210 cli.DockerCmd(c, "save", "-o", "saveimg.tar", myImageName) 211 cli.DockerCmd(c, "rmi", myImageName) 212 out = cli.DockerCmd(c, "images", "-q", myImageName).Stdout() 213 noImageID := strings.TrimSpace(out) 214 assert.Equal(c, noImageID, "", "Should not have any image") 215 cli.DockerCmd(c, "load", "-i", "saveimg.tar") 216 217 result := icmd.RunCommand("rm", "-rf", "saveimg.tar") 218 result.Assert(c, icmd.Success) 219 220 out = cli.DockerCmd(c, "images", "-q", "--no-trunc", myImageName).Stdout() 221 imageID := strings.TrimSpace(out) 222 assert.Equal(c, imageID, longImageID, "Should have same image id as before") 223 224 out = cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=load").Stdout() 225 events := strings.Split(strings.TrimSpace(out), "\n") 226 assert.Equal(c, len(events), 1) 227 matches := eventstestutils.ScanMap(events[0]) 228 assert.Equal(c, matches["id"], imageID, "matches: %v\nout:\n%s\n", matches, out) 229 assert.Equal(c, matches["action"], "load", "matches: %v\nout:\n%s\n", matches, out) 230 231 out = cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=save").Stdout() 232 events = strings.Split(strings.TrimSpace(out), "\n") 233 assert.Equal(c, len(events), 1) 234 matches = eventstestutils.ScanMap(events[0]) 235 assert.Equal(c, matches["id"], imageID, "matches: %v\nout:\n%s\n", matches, out) 236 assert.Equal(c, matches["action"], "save", "matches: %v\nout:\n%s\n", matches, out) 237 } 238 239 func (s *DockerCLIEventSuite) TestEventsPluginOps(c *testing.T) { 240 testRequires(c, DaemonIsLinux, IsAmd64, Network) 241 242 since := daemonUnixTime(c) 243 244 cli.DockerCmd(c, "plugin", "install", pNameWithTag, "--grant-all-permissions") 245 cli.DockerCmd(c, "plugin", "disable", pNameWithTag) 246 cli.DockerCmd(c, "plugin", "remove", pNameWithTag) 247 248 out := cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c)).Stdout() 249 events := strings.Split(out, "\n") 250 events = events[:len(events)-1] 251 252 assert.Assert(c, len(events) >= 4) 253 254 pluginEvents := eventActionsByIDAndType(c, events, pNameWithTag, "plugin") 255 assert.Assert(c, is.DeepEqual(pluginEvents, []string{"pull", "enable", "disable", "remove"}), out) 256 } 257 258 func (s *DockerCLIEventSuite) TestEventsFilters(c *testing.T) { 259 since := daemonUnixTime(c) 260 cli.DockerCmd(c, "run", "--rm", "busybox", "true") 261 cli.DockerCmd(c, "run", "--rm", "busybox", "true") 262 out := cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=die").Stdout() 263 parseEvents(c, out, "die") 264 265 out = cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=die", "--filter", "event=start").Stdout() 266 parseEvents(c, out, "die|start") 267 268 // make sure we at least got 2 start events 269 count := strings.Count(out, "start") 270 assert.Assert(c, count >= 2, "should have had 2 start events but had %d, out: %s", count, out) 271 } 272 273 func (s *DockerCLIEventSuite) TestEventsFilterImageName(c *testing.T) { 274 since := daemonUnixTime(c) 275 276 out := cli.DockerCmd(c, "run", "--name", "container_1", "-d", "busybox:latest", "true").Stdout() 277 container1 := strings.TrimSpace(out) 278 279 out = cli.DockerCmd(c, "run", "--name", "container_2", "-d", "busybox", "true").Stdout() 280 container2 := strings.TrimSpace(out) 281 282 name := "busybox" 283 out = cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("image=%s", name)).Stdout() 284 events := strings.Split(out, "\n") 285 events = events[:len(events)-1] 286 assert.Assert(c, len(events) != 0, "Expected events but found none for the image busybox:latest") 287 count1 := 0 288 count2 := 0 289 290 for _, e := range events { 291 if strings.Contains(e, container1) { 292 count1++ 293 } else if strings.Contains(e, container2) { 294 count2++ 295 } 296 } 297 assert.Assert(c, count1 != 0, "Expected event from container but got %d from %s", count1, container1) 298 assert.Assert(c, count2 != 0, "Expected event from container but got %d from %s", count2, container2) 299 } 300 301 func (s *DockerCLIEventSuite) TestEventsFilterLabels(c *testing.T) { 302 since := strconv.FormatUint(uint64(daemonTime(c).Unix()), 10) 303 label := "io.docker.testing=foo" 304 305 result := cli.DockerCmd(c, "create", "-l", label, "busybox") 306 assert.Equal(c, result.ExitCode, 0) 307 container1 := strings.TrimSpace(result.Stdout()) 308 309 result = cli.DockerCmd(c, "create", "busybox") 310 assert.Equal(c, result.ExitCode, 0) 311 container2 := strings.TrimSpace(result.Stdout()) 312 313 // fetch events with `--until`, so that the client detaches after a second 314 // instead of staying attached, waiting for more events to arrive. 315 out := cli.DockerCmd(c, 316 "events", 317 "--since", since, 318 "--until", strconv.FormatUint(uint64(daemonTime(c).Add(time.Second).Unix()), 10), 319 "--filter", "label="+label, 320 ).Stdout() 321 322 events := strings.Split(strings.TrimSpace(out), "\n") 323 assert.Assert(c, len(events) > 0) 324 325 var found bool 326 for _, e := range events { 327 if strings.Contains(e, container1) { 328 found = true 329 } 330 assert.Assert(c, !strings.Contains(e, container2)) 331 } 332 assert.Assert(c, found) 333 } 334 335 func (s *DockerCLIEventSuite) TestEventsFilterImageLabels(c *testing.T) { 336 since := daemonUnixTime(c) 337 name := "labelfiltertest" 338 label := "io.docker.testing=image" 339 340 // Build a test image. 341 buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(` 342 FROM busybox:latest 343 LABEL %s`, label))) 344 cli.DockerCmd(c, "tag", name, "labelfiltertest:tag1") 345 cli.DockerCmd(c, "tag", name, "labelfiltertest:tag2") 346 cli.DockerCmd(c, "tag", "busybox:latest", "labelfiltertest:tag3") 347 348 out := cli.DockerCmd(c, 349 "events", 350 "--since", since, 351 "--until", daemonUnixTime(c), 352 "--filter", fmt.Sprintf("label=%s", label), 353 "--filter", "type=image", 354 ).Stdout() 355 356 events := strings.Split(strings.TrimSpace(out), "\n") 357 358 // 2 events from the "docker tag" command, another one is from "docker build" 359 assert.Equal(c, len(events), 3, "Events == %s", events) 360 for _, e := range events { 361 assert.Check(c, strings.Contains(e, "labelfiltertest")) 362 } 363 } 364 365 func (s *DockerCLIEventSuite) TestEventsFilterContainer(c *testing.T) { 366 since := daemonUnixTime(c) 367 nameID := make(map[string]string) 368 369 for _, name := range []string{"container_1", "container_2"} { 370 cli.DockerCmd(c, "run", "--name", name, "busybox", "true") 371 id := inspectField(c, name, "Id") 372 nameID[name] = id 373 } 374 375 until := daemonUnixTime(c) 376 377 checkEvents := func(id string, events []string) error { 378 if len(events) != 4 { // create, attach, start, die 379 return fmt.Errorf("expected 4 events, got %v", events) 380 } 381 for _, event := range events { 382 matches := eventstestutils.ScanMap(event) 383 if !matchEventID(matches, id) { 384 return fmt.Errorf("expected event for container id %s: %s - parsed container id: %s", id, event, matches["id"]) 385 } 386 } 387 return nil 388 } 389 390 for name, ID := range nameID { 391 // filter by names 392 out := cli.DockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+name).Stdout() 393 events := strings.Split(strings.TrimSuffix(out, "\n"), "\n") 394 assert.NilError(c, checkEvents(ID, events)) 395 396 // filter by ID's 397 out = cli.DockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+ID).Stdout() 398 events = strings.Split(strings.TrimSuffix(out, "\n"), "\n") 399 assert.NilError(c, checkEvents(ID, events)) 400 } 401 } 402 403 func (s *DockerCLIEventSuite) TestEventsCommit(c *testing.T) { 404 // Problematic on Windows as cannot commit a running container 405 testRequires(c, DaemonIsLinux) 406 407 cID := runSleepingContainer(c) 408 cli.WaitRun(c, cID) 409 410 cli.DockerCmd(c, "commit", "-m", "test", cID) 411 cli.DockerCmd(c, "stop", cID) 412 cli.WaitExited(c, cID, 5*time.Second) 413 414 until := daemonUnixTime(c) 415 out := cli.DockerCmd(c, "events", "-f", "container="+cID, "--until="+until).Combined() 416 assert.Assert(c, strings.Contains(out, "commit"), "Missing 'commit' log event") 417 } 418 419 func (s *DockerCLIEventSuite) TestEventsCopy(c *testing.T) { 420 // Build a test image. 421 buildImageSuccessfully(c, "cpimg", build.WithDockerfile(` 422 FROM busybox 423 RUN echo HI > /file`)) 424 id := getIDByName(c, "cpimg") 425 426 // Create an empty test file. 427 tempFile, err := os.CreateTemp("", "test-events-copy-") 428 assert.NilError(c, err) 429 defer os.Remove(tempFile.Name()) 430 431 assert.NilError(c, tempFile.Close()) 432 433 cli.DockerCmd(c, "create", "--name=cptest", id) 434 435 cli.DockerCmd(c, "cp", "cptest:/file", tempFile.Name()) 436 437 until := daemonUnixTime(c) 438 out := cli.DockerCmd(c, "events", "--since=0", "-f", "container=cptest", "--until="+until).Stdout() 439 assert.Assert(c, strings.Contains(out, "archive-path"), "Missing 'archive-path' log event") 440 441 cli.DockerCmd(c, "cp", tempFile.Name(), "cptest:/filecopy") 442 443 until = daemonUnixTime(c) 444 out = cli.DockerCmd(c, "events", "-f", "container=cptest", "--until="+until).Stdout() 445 assert.Assert(c, strings.Contains(out, "extract-to-dir"), "Missing 'extract-to-dir' log event") 446 } 447 448 func (s *DockerCLIEventSuite) TestEventsResize(c *testing.T) { 449 cID := runSleepingContainer(c, "-d", "-t") 450 cli.WaitRun(c, cID) 451 452 apiClient, err := client.NewClientWithOpts(client.FromEnv) 453 assert.NilError(c, err) 454 defer apiClient.Close() 455 456 options := container.ResizeOptions{ 457 Height: 80, 458 Width: 24, 459 } 460 err = apiClient.ContainerResize(testutil.GetContext(c), cID, options) 461 assert.NilError(c, err) 462 463 cli.DockerCmd(c, "stop", cID) 464 465 until := daemonUnixTime(c) 466 out := cli.DockerCmd(c, "events", "-f", "container="+cID, "--until="+until).Combined() 467 assert.Assert(c, strings.Contains(out, "resize"), "Missing 'resize' log event") 468 } 469 470 func (s *DockerCLIEventSuite) TestEventsAttach(c *testing.T) { 471 // TODO Windows CI: Figure out why this test fails intermittently (TP5). 472 testRequires(c, DaemonIsLinux) 473 474 out := cli.DockerCmd(c, "run", "-di", "busybox", "cat").Combined() 475 cID := strings.TrimSpace(out) 476 cli.WaitRun(c, cID) 477 478 cmd := exec.Command(dockerBinary, "attach", cID) 479 stdin, err := cmd.StdinPipe() 480 assert.NilError(c, err) 481 defer stdin.Close() 482 stdout, err := cmd.StdoutPipe() 483 assert.NilError(c, err) 484 defer stdout.Close() 485 assert.NilError(c, cmd.Start()) 486 defer func() { 487 cmd.Process.Kill() 488 cmd.Wait() 489 }() 490 491 // Make sure we're done attaching by writing/reading some stuff 492 _, err = stdin.Write([]byte("hello\n")) 493 assert.NilError(c, err) 494 out, err = bufio.NewReader(stdout).ReadString('\n') 495 assert.NilError(c, err) 496 assert.Equal(c, strings.TrimSpace(out), "hello") 497 498 assert.NilError(c, stdin.Close()) 499 500 cli.DockerCmd(c, "kill", cID) 501 cli.WaitExited(c, cID, 5*time.Second) 502 503 until := daemonUnixTime(c) 504 out = cli.DockerCmd(c, "events", "-f", "container="+cID, "--until="+until).Combined() 505 assert.Assert(c, strings.Contains(out, "attach"), "Missing 'attach' log event") 506 } 507 508 func (s *DockerCLIEventSuite) TestEventsRename(c *testing.T) { 509 out := cli.DockerCmd(c, "run", "--name", "oldName", "busybox", "true").Stdout() 510 cID := strings.TrimSpace(out) 511 cli.DockerCmd(c, "rename", "oldName", "newName") 512 513 until := daemonUnixTime(c) 514 // filter by the container id because the name in the event will be the new name. 515 out = cli.DockerCmd(c, "events", "-f", "container="+cID, "--until", until).Stdout() 516 assert.Assert(c, strings.Contains(out, "rename"), "Missing 'rename' log event") 517 } 518 519 func (s *DockerCLIEventSuite) TestEventsTop(c *testing.T) { 520 // Problematic on Windows as Windows does not support top 521 testRequires(c, DaemonIsLinux) 522 523 cID := runSleepingContainer(c, "-d") 524 cli.WaitRun(c, cID) 525 526 cli.DockerCmd(c, "top", cID) 527 cli.DockerCmd(c, "stop", cID) 528 529 until := daemonUnixTime(c) 530 out := cli.DockerCmd(c, "events", "-f", "container="+cID, "--until="+until).Combined() 531 assert.Assert(c, strings.Contains(out, "top"), "Missing 'top' log event") 532 } 533 534 // #14316 535 func (s *DockerRegistrySuite) TestEventsImageFilterPush(c *testing.T) { 536 // Problematic to port for Windows CI during TP5 timeframe until 537 // supporting push 538 testRequires(c, DaemonIsLinux) 539 testRequires(c, Network) 540 imgRepoName := fmt.Sprintf("%v/dockercli/testf", privateRegistryURL) 541 542 out := cli.DockerCmd(c, "run", "-d", "busybox", "top").Stdout() 543 cID := strings.TrimSpace(out) 544 cli.WaitRun(c, cID) 545 546 cli.DockerCmd(c, "commit", cID, imgRepoName) 547 cli.DockerCmd(c, "stop", cID) 548 cli.DockerCmd(c, "push", imgRepoName) 549 550 until := daemonUnixTime(c) 551 out = cli.DockerCmd(c, "events", "-f", "image="+imgRepoName, "-f", "event=push", "--until", until).Stdout() 552 assert.Assert(c, strings.Contains(out, imgRepoName), "Missing 'push' log event for %s", imgRepoName) 553 } 554 555 func (s *DockerCLIEventSuite) TestEventsFilterType(c *testing.T) { 556 // FIXME(vdemeester) fails on e2e run 557 testRequires(c, testEnv.IsLocalDaemon) 558 since := daemonUnixTime(c) 559 name := "labelfiltertest" 560 label := "io.docker.testing=image" 561 562 // Build a test image. 563 buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(` 564 FROM busybox:latest 565 LABEL %s`, label))) 566 cli.DockerCmd(c, "tag", name, "labelfiltertest:tag1") 567 cli.DockerCmd(c, "tag", name, "labelfiltertest:tag2") 568 cli.DockerCmd(c, "tag", "busybox:latest", "labelfiltertest:tag3") 569 570 out := cli.DockerCmd(c, 571 "events", 572 "--since", since, 573 "--until", daemonUnixTime(c), 574 "--filter", fmt.Sprintf("label=%s", label), 575 "--filter", "type=image", 576 ).Stdout() 577 578 events := strings.Split(strings.TrimSpace(out), "\n") 579 580 // 2 events from the "docker tag" command, another one is from "docker build" 581 assert.Equal(c, len(events), 3, "Events == %s", events) 582 for _, e := range events { 583 assert.Check(c, strings.Contains(e, "labelfiltertest")) 584 } 585 586 out = cli.DockerCmd(c, 587 "events", 588 "--since", since, 589 "--until", daemonUnixTime(c), 590 "--filter", fmt.Sprintf("label=%s", label), 591 "--filter", "type=container", 592 ).Stdout() 593 events = strings.Split(strings.TrimSpace(out), "\n") 594 595 // Events generated by the container that builds the image 596 assert.Equal(c, len(events), 2, "Events == %s", events) 597 598 out = cli.DockerCmd(c, 599 "events", 600 "--since", since, 601 "--until", daemonUnixTime(c), 602 "--filter", "type=network", 603 ).Stdout() 604 events = strings.Split(strings.TrimSpace(out), "\n") 605 assert.Assert(c, len(events) >= 1, "Events == %s", events) 606 } 607 608 // #25798 609 func (s *DockerCLIEventSuite) TestEventsSpecialFiltersWithExecCreate(c *testing.T) { 610 since := daemonUnixTime(c) 611 runSleepingContainer(c, "--name", "test-container", "-d") 612 cli.WaitRun(c, "test-container") 613 614 cli.DockerCmd(c, "exec", "test-container", "echo", "hello-world") 615 616 out := cli.DockerCmd(c, 617 "events", 618 "--since", since, 619 "--until", daemonUnixTime(c), 620 "--filter", 621 "event='exec_create: echo hello-world'", 622 ).Stdout() 623 624 events := strings.Split(strings.TrimSpace(out), "\n") 625 assert.Equal(c, len(events), 1, out) 626 627 out = cli.DockerCmd(c, 628 "events", 629 "--since", since, 630 "--until", daemonUnixTime(c), 631 "--filter", 632 "event=exec_create", 633 ).Stdout() 634 assert.Equal(c, len(events), 1, out) 635 } 636 637 func (s *DockerCLIEventSuite) TestEventsFilterImageInContainerAction(c *testing.T) { 638 since := daemonUnixTime(c) 639 cli.DockerCmd(c, "run", "-d", "busybox", "true") 640 641 out := cli.DockerCmd(c, "events", "--filter", "image=busybox", "--since", since, "--until", daemonUnixTime(c)).Stdout() 642 events := strings.Split(strings.TrimSpace(out), "\n") 643 assert.Assert(c, len(events) > 1, out) 644 } 645 646 func (s *DockerCLIEventSuite) TestEventsContainerRestart(c *testing.T) { 647 cli.DockerCmd(c, "run", "-d", "--name=testEvent", "--restart=on-failure:3", "busybox", "false") 648 649 // wait until test2 is auto removed. 650 waitTime := 10 * time.Second 651 if testEnv.DaemonInfo.OSType == "windows" { 652 // Windows takes longer... 653 waitTime = 90 * time.Second 654 } 655 656 err := waitInspect("testEvent", "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTime) 657 assert.NilError(c, err) 658 659 var ( 660 createCount int 661 startCount int 662 dieCount int 663 ) 664 out := cli.DockerCmd(c, "events", "--since=0", "--until", daemonUnixTime(c), "-f", "container=testEvent").Stdout() 665 events := strings.Split(strings.TrimSpace(out), "\n") 666 667 nEvents := len(events) 668 assert.Assert(c, nEvents >= 1) 669 actions := eventActionsByIDAndType(c, events, "testEvent", "container") 670 671 for _, a := range actions { 672 switch a { 673 case "create": 674 createCount++ 675 case "start": 676 startCount++ 677 case "die": 678 dieCount++ 679 } 680 } 681 assert.Equal(c, createCount, 1, "testEvent should be created 1 times: %v", actions) 682 assert.Equal(c, startCount, 4, "testEvent should start 4 times: %v", actions) 683 assert.Equal(c, dieCount, 4, "testEvent should die 4 times: %v", actions) 684 } 685 686 func (s *DockerCLIEventSuite) TestEventsSinceInTheFuture(c *testing.T) { 687 cli.DockerCmd(c, "run", "--name", "test-container", "-d", "busybox", "true") 688 689 since := daemonTime(c) 690 until := since.Add(time.Duration(-24) * time.Hour) 691 out, _, err := dockerCmdWithError("events", "--filter", "image=busybox", "--since", parseEventTime(since), "--until", parseEventTime(until)) 692 693 assert.ErrorContains(c, err, "") 694 assert.Assert(c, strings.Contains(out, "cannot be after `until`")) 695 } 696 697 func (s *DockerCLIEventSuite) TestEventsUntilInThePast(c *testing.T) { 698 since := daemonUnixTime(c) 699 700 cli.DockerCmd(c, "run", "--name", "test-container", "-d", "busybox", "true") 701 702 until := daemonUnixTime(c) 703 704 cli.DockerCmd(c, "run", "--name", "test-container2", "-d", "busybox", "true") 705 706 out := cli.DockerCmd(c, "events", "--filter", "image=busybox", "--since", since, "--until", until).Stdout() 707 708 assert.Assert(c, !strings.Contains(out, "test-container2")) 709 assert.Assert(c, strings.Contains(out, "test-container")) 710 } 711 712 func (s *DockerCLIEventSuite) TestEventsFormat(c *testing.T) { 713 since := daemonUnixTime(c) 714 cli.DockerCmd(c, "run", "--rm", "busybox", "true") 715 cli.DockerCmd(c, "run", "--rm", "busybox", "true") 716 out := cli.DockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--format", "{{json .}}").Stdout() 717 dec := json.NewDecoder(strings.NewReader(out)) 718 // make sure we got 2 start events 719 startCount := 0 720 for { 721 var err error 722 var ev eventtypes.Message 723 if err = dec.Decode(&ev); err == io.EOF { 724 break 725 } 726 assert.NilError(c, err) 727 if ev.Action == eventtypes.ActionStart { 728 startCount++ 729 } 730 } 731 732 assert.Equal(c, startCount, 2, "should have had 2 start events but had %d, out: %s", startCount, out) 733 } 734 735 func (s *DockerCLIEventSuite) TestEventsFormatBadFunc(c *testing.T) { 736 // make sure it fails immediately, without receiving any event 737 result := cli.Docker(cli.Args("events", "--format", "{{badFuncString .}}")) 738 result.Assert(c, icmd.Expected{ 739 Error: "exit status 64", 740 ExitCode: 64, 741 Err: `Error parsing format: template: :1: function "badFuncString" not defined`, 742 }) 743 } 744 745 func (s *DockerCLIEventSuite) TestEventsFormatBadField(c *testing.T) { 746 // make sure it fails immediately, without receiving any event 747 result := cli.Docker(cli.Args("events", "--format", "{{.badFieldString}}")) 748 result.Assert(c, icmd.Expected{ 749 Error: "exit status 64", 750 ExitCode: 64, 751 Err: `Error parsing format: template: :1:2: executing "" at <.badFieldString>: can't evaluate field badFieldString in type *events.Message`, 752 }) 753 }