github.com/stevegt/moby@v1.13.1/integration-cli/docker_cli_events_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bufio" 7 "bytes" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "strings" 13 "syscall" 14 "time" 15 "unicode" 16 17 "github.com/docker/docker/pkg/integration/checker" 18 "github.com/go-check/check" 19 "github.com/kr/pty" 20 ) 21 22 // #5979 23 func (s *DockerSuite) TestEventsRedirectStdout(c *check.C) { 24 since := daemonUnixTime(c) 25 dockerCmd(c, "run", "busybox", "true") 26 27 file, err := ioutil.TempFile("", "") 28 c.Assert(err, checker.IsNil, check.Commentf("could not create temp file")) 29 defer os.Remove(file.Name()) 30 31 command := fmt.Sprintf("%s events --since=%s --until=%s > %s", dockerBinary, since, daemonUnixTime(c), file.Name()) 32 _, tty, err := pty.Open() 33 c.Assert(err, checker.IsNil, check.Commentf("Could not open pty")) 34 cmd := exec.Command("sh", "-c", command) 35 cmd.Stdin = tty 36 cmd.Stdout = tty 37 cmd.Stderr = tty 38 c.Assert(cmd.Run(), checker.IsNil, check.Commentf("run err for command %q", command)) 39 40 scanner := bufio.NewScanner(file) 41 for scanner.Scan() { 42 for _, ch := range scanner.Text() { 43 c.Assert(unicode.IsControl(ch), checker.False, check.Commentf("found control character %v", []byte(string(ch)))) 44 } 45 } 46 c.Assert(scanner.Err(), checker.IsNil, check.Commentf("Scan err for command %q", command)) 47 48 } 49 50 func (s *DockerSuite) TestEventsOOMDisableFalse(c *check.C) { 51 testRequires(c, DaemonIsLinux, oomControl, memoryLimitSupport, swapMemorySupport) 52 53 errChan := make(chan error) 54 go func() { 55 defer close(errChan) 56 out, exitCode, _ := dockerCmdWithError("run", "--name", "oomFalse", "-m", "10MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done") 57 if expected := 137; exitCode != expected { 58 errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out) 59 } 60 }() 61 select { 62 case err := <-errChan: 63 c.Assert(err, checker.IsNil) 64 case <-time.After(30 * time.Second): 65 c.Fatal("Timeout waiting for container to die on OOM") 66 } 67 68 out, _ := dockerCmd(c, "events", "--since=0", "-f", "container=oomFalse", "--until", daemonUnixTime(c)) 69 events := strings.Split(strings.TrimSuffix(out, "\n"), "\n") 70 nEvents := len(events) 71 72 c.Assert(nEvents, checker.GreaterOrEqualThan, 5) //Missing expected event 73 c.Assert(parseEventAction(c, events[nEvents-5]), checker.Equals, "create") 74 c.Assert(parseEventAction(c, events[nEvents-4]), checker.Equals, "attach") 75 c.Assert(parseEventAction(c, events[nEvents-3]), checker.Equals, "start") 76 c.Assert(parseEventAction(c, events[nEvents-2]), checker.Equals, "oom") 77 c.Assert(parseEventAction(c, events[nEvents-1]), checker.Equals, "die") 78 } 79 80 func (s *DockerSuite) TestEventsOOMDisableTrue(c *check.C) { 81 testRequires(c, DaemonIsLinux, oomControl, memoryLimitSupport, NotArm, swapMemorySupport) 82 83 errChan := make(chan error) 84 observer, err := newEventObserver(c) 85 c.Assert(err, checker.IsNil) 86 err = observer.Start() 87 c.Assert(err, checker.IsNil) 88 defer observer.Stop() 89 90 go func() { 91 defer close(errChan) 92 out, exitCode, _ := dockerCmdWithError("run", "--oom-kill-disable=true", "--name", "oomTrue", "-m", "10MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done") 93 if expected := 137; exitCode != expected { 94 errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out) 95 } 96 }() 97 98 c.Assert(waitRun("oomTrue"), checker.IsNil) 99 defer dockerCmd(c, "kill", "oomTrue") 100 containerID := inspectField(c, "oomTrue", "Id") 101 102 testActions := map[string]chan bool{ 103 "oom": make(chan bool), 104 } 105 106 matcher := matchEventLine(containerID, "container", testActions) 107 processor := processEventMatch(testActions) 108 go observer.Match(matcher, processor) 109 110 select { 111 case <-time.After(20 * time.Second): 112 observer.CheckEventError(c, containerID, "oom", matcher) 113 case <-testActions["oom"]: 114 // ignore, done 115 case errRun := <-errChan: 116 if errRun != nil { 117 c.Fatalf("%v", errRun) 118 } else { 119 c.Fatalf("container should be still running but it's not") 120 } 121 } 122 123 status := inspectField(c, "oomTrue", "State.Status") 124 c.Assert(strings.TrimSpace(status), checker.Equals, "running", check.Commentf("container should be still running")) 125 } 126 127 // #18453 128 func (s *DockerSuite) TestEventsContainerFilterByName(c *check.C) { 129 testRequires(c, DaemonIsLinux) 130 cOut, _ := dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top") 131 c1 := strings.TrimSpace(cOut) 132 waitRun("foo") 133 cOut, _ = dockerCmd(c, "run", "--name=bar", "-d", "busybox", "top") 134 c2 := strings.TrimSpace(cOut) 135 waitRun("bar") 136 out, _ := dockerCmd(c, "events", "-f", "container=foo", "--since=0", "--until", daemonUnixTime(c)) 137 c.Assert(out, checker.Contains, c1, check.Commentf(out)) 138 c.Assert(out, checker.Not(checker.Contains), c2, check.Commentf(out)) 139 } 140 141 // #18453 142 func (s *DockerSuite) TestEventsContainerFilterBeforeCreate(c *check.C) { 143 testRequires(c, DaemonIsLinux) 144 buf := &bytes.Buffer{} 145 cmd := exec.Command(dockerBinary, "events", "-f", "container=foo", "--since=0") 146 cmd.Stdout = buf 147 c.Assert(cmd.Start(), check.IsNil) 148 defer cmd.Wait() 149 defer cmd.Process.Kill() 150 151 // Sleep for a second to make sure we are testing the case where events are listened before container starts. 152 time.Sleep(time.Second) 153 id, _ := dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top") 154 cID := strings.TrimSpace(id) 155 for i := 0; ; i++ { 156 out := buf.String() 157 if strings.Contains(out, cID) { 158 break 159 } 160 if i > 30 { 161 c.Fatalf("Missing event of container (foo, %v), got %q", cID, out) 162 } 163 time.Sleep(500 * time.Millisecond) 164 } 165 } 166 167 func (s *DockerSuite) TestVolumeEvents(c *check.C) { 168 testRequires(c, DaemonIsLinux) 169 170 since := daemonUnixTime(c) 171 172 // Observe create/mount volume actions 173 dockerCmd(c, "volume", "create", "test-event-volume-local") 174 dockerCmd(c, "run", "--name", "test-volume-container", "--volume", "test-event-volume-local:/foo", "-d", "busybox", "true") 175 waitRun("test-volume-container") 176 177 // Observe unmount/destroy volume actions 178 dockerCmd(c, "rm", "-f", "test-volume-container") 179 dockerCmd(c, "volume", "rm", "test-event-volume-local") 180 181 until := daemonUnixTime(c) 182 out, _ := dockerCmd(c, "events", "--since", since, "--until", until) 183 events := strings.Split(strings.TrimSpace(out), "\n") 184 c.Assert(len(events), checker.GreaterThan, 4) 185 186 volumeEvents := eventActionsByIDAndType(c, events, "test-event-volume-local", "volume") 187 c.Assert(volumeEvents, checker.HasLen, 4) 188 c.Assert(volumeEvents[0], checker.Equals, "create") 189 c.Assert(volumeEvents[1], checker.Equals, "mount") 190 c.Assert(volumeEvents[2], checker.Equals, "unmount") 191 c.Assert(volumeEvents[3], checker.Equals, "destroy") 192 } 193 194 func (s *DockerSuite) TestNetworkEvents(c *check.C) { 195 testRequires(c, DaemonIsLinux) 196 197 since := daemonUnixTime(c) 198 199 // Observe create/connect network actions 200 dockerCmd(c, "network", "create", "test-event-network-local") 201 dockerCmd(c, "run", "--name", "test-network-container", "--net", "test-event-network-local", "-d", "busybox", "true") 202 waitRun("test-network-container") 203 204 // Observe disconnect/destroy network actions 205 dockerCmd(c, "rm", "-f", "test-network-container") 206 dockerCmd(c, "network", "rm", "test-event-network-local") 207 208 until := daemonUnixTime(c) 209 out, _ := dockerCmd(c, "events", "--since", since, "--until", until) 210 events := strings.Split(strings.TrimSpace(out), "\n") 211 c.Assert(len(events), checker.GreaterThan, 4) 212 213 netEvents := eventActionsByIDAndType(c, events, "test-event-network-local", "network") 214 c.Assert(netEvents, checker.HasLen, 4) 215 c.Assert(netEvents[0], checker.Equals, "create") 216 c.Assert(netEvents[1], checker.Equals, "connect") 217 c.Assert(netEvents[2], checker.Equals, "disconnect") 218 c.Assert(netEvents[3], checker.Equals, "destroy") 219 } 220 221 func (s *DockerSuite) TestEventsContainerWithMultiNetwork(c *check.C) { 222 testRequires(c, DaemonIsLinux) 223 224 // Observe create/connect network actions 225 dockerCmd(c, "network", "create", "test-event-network-local-1") 226 dockerCmd(c, "network", "create", "test-event-network-local-2") 227 dockerCmd(c, "run", "--name", "test-network-container", "--net", "test-event-network-local-1", "-td", "busybox", "sh") 228 waitRun("test-network-container") 229 dockerCmd(c, "network", "connect", "test-event-network-local-2", "test-network-container") 230 231 since := daemonUnixTime(c) 232 233 dockerCmd(c, "stop", "-t", "1", "test-network-container") 234 235 until := daemonUnixTime(c) 236 out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "-f", "type=network") 237 netEvents := strings.Split(strings.TrimSpace(out), "\n") 238 239 // received two network disconnect events 240 c.Assert(len(netEvents), checker.Equals, 2) 241 c.Assert(netEvents[0], checker.Contains, "disconnect") 242 c.Assert(netEvents[1], checker.Contains, "disconnect") 243 244 //both networks appeared in the network event output 245 c.Assert(out, checker.Contains, "test-event-network-local-1") 246 c.Assert(out, checker.Contains, "test-event-network-local-2") 247 } 248 249 func (s *DockerSuite) TestEventsStreaming(c *check.C) { 250 testRequires(c, DaemonIsLinux) 251 252 observer, err := newEventObserver(c) 253 c.Assert(err, checker.IsNil) 254 err = observer.Start() 255 c.Assert(err, checker.IsNil) 256 defer observer.Stop() 257 258 out, _ := dockerCmd(c, "run", "-d", "busybox:latest", "true") 259 containerID := strings.TrimSpace(out) 260 261 testActions := map[string]chan bool{ 262 "create": make(chan bool, 1), 263 "start": make(chan bool, 1), 264 "die": make(chan bool, 1), 265 "destroy": make(chan bool, 1), 266 } 267 268 matcher := matchEventLine(containerID, "container", testActions) 269 processor := processEventMatch(testActions) 270 go observer.Match(matcher, processor) 271 272 select { 273 case <-time.After(5 * time.Second): 274 observer.CheckEventError(c, containerID, "create", matcher) 275 case <-testActions["create"]: 276 // ignore, done 277 } 278 279 select { 280 case <-time.After(5 * time.Second): 281 observer.CheckEventError(c, containerID, "start", matcher) 282 case <-testActions["start"]: 283 // ignore, done 284 } 285 286 select { 287 case <-time.After(5 * time.Second): 288 observer.CheckEventError(c, containerID, "die", matcher) 289 case <-testActions["die"]: 290 // ignore, done 291 } 292 293 dockerCmd(c, "rm", containerID) 294 295 select { 296 case <-time.After(5 * time.Second): 297 observer.CheckEventError(c, containerID, "destroy", matcher) 298 case <-testActions["destroy"]: 299 // ignore, done 300 } 301 } 302 303 func (s *DockerSuite) TestEventsImageUntagDelete(c *check.C) { 304 testRequires(c, DaemonIsLinux) 305 306 observer, err := newEventObserver(c) 307 c.Assert(err, checker.IsNil) 308 err = observer.Start() 309 c.Assert(err, checker.IsNil) 310 defer observer.Stop() 311 312 name := "testimageevents" 313 imageID, err := buildImage(name, 314 `FROM scratch 315 MAINTAINER "docker"`, 316 true) 317 c.Assert(err, checker.IsNil) 318 c.Assert(deleteImages(name), checker.IsNil) 319 320 testActions := map[string]chan bool{ 321 "untag": make(chan bool, 1), 322 "delete": make(chan bool, 1), 323 } 324 325 matcher := matchEventLine(imageID, "image", testActions) 326 processor := processEventMatch(testActions) 327 go observer.Match(matcher, processor) 328 329 select { 330 case <-time.After(10 * time.Second): 331 observer.CheckEventError(c, imageID, "untag", matcher) 332 case <-testActions["untag"]: 333 // ignore, done 334 } 335 336 select { 337 case <-time.After(10 * time.Second): 338 observer.CheckEventError(c, imageID, "delete", matcher) 339 case <-testActions["delete"]: 340 // ignore, done 341 } 342 } 343 344 func (s *DockerSuite) TestEventsFilterVolumeAndNetworkType(c *check.C) { 345 testRequires(c, DaemonIsLinux) 346 347 since := daemonUnixTime(c) 348 349 dockerCmd(c, "network", "create", "test-event-network-type") 350 dockerCmd(c, "volume", "create", "test-event-volume-type") 351 352 out, _ := dockerCmd(c, "events", "--filter", "type=volume", "--filter", "type=network", "--since", since, "--until", daemonUnixTime(c)) 353 events := strings.Split(strings.TrimSpace(out), "\n") 354 c.Assert(len(events), checker.GreaterOrEqualThan, 2, check.Commentf(out)) 355 356 networkActions := eventActionsByIDAndType(c, events, "test-event-network-type", "network") 357 volumeActions := eventActionsByIDAndType(c, events, "test-event-volume-type", "volume") 358 359 c.Assert(volumeActions[0], checker.Equals, "create") 360 c.Assert(networkActions[0], checker.Equals, "create") 361 } 362 363 func (s *DockerSuite) TestEventsFilterVolumeID(c *check.C) { 364 testRequires(c, DaemonIsLinux) 365 366 since := daemonUnixTime(c) 367 368 dockerCmd(c, "volume", "create", "test-event-volume-id") 369 out, _ := dockerCmd(c, "events", "--filter", "volume=test-event-volume-id", "--since", since, "--until", daemonUnixTime(c)) 370 events := strings.Split(strings.TrimSpace(out), "\n") 371 c.Assert(events, checker.HasLen, 1) 372 373 c.Assert(events[0], checker.Contains, "test-event-volume-id") 374 c.Assert(events[0], checker.Contains, "driver=local") 375 } 376 377 func (s *DockerSuite) TestEventsFilterNetworkID(c *check.C) { 378 testRequires(c, DaemonIsLinux) 379 380 since := daemonUnixTime(c) 381 382 dockerCmd(c, "network", "create", "test-event-network-local") 383 out, _ := dockerCmd(c, "events", "--filter", "network=test-event-network-local", "--since", since, "--until", daemonUnixTime(c)) 384 events := strings.Split(strings.TrimSpace(out), "\n") 385 c.Assert(events, checker.HasLen, 1) 386 387 c.Assert(events[0], checker.Contains, "test-event-network-local") 388 c.Assert(events[0], checker.Contains, "type=bridge") 389 } 390 391 func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) { 392 testRequires(c, SameHostDaemon, DaemonIsLinux) 393 394 // daemon config file 395 configFilePath := "test.json" 396 configFile, err := os.Create(configFilePath) 397 c.Assert(err, checker.IsNil) 398 defer os.Remove(configFilePath) 399 400 daemonConfig := `{"labels":["foo=bar"]}` 401 fmt.Fprintf(configFile, "%s", daemonConfig) 402 configFile.Close() 403 c.Assert(s.d.Start(fmt.Sprintf("--config-file=%s", configFilePath)), check.IsNil) 404 405 // Get daemon ID 406 out, err := s.d.Cmd("info") 407 c.Assert(err, checker.IsNil) 408 daemonID := "" 409 daemonName := "" 410 for _, line := range strings.Split(out, "\n") { 411 if strings.HasPrefix(line, "ID: ") { 412 daemonID = strings.TrimPrefix(line, "ID: ") 413 } else if strings.HasPrefix(line, "Name: ") { 414 daemonName = strings.TrimPrefix(line, "Name: ") 415 } 416 } 417 c.Assert(daemonID, checker.Not(checker.Equals), "") 418 419 configFile, err = os.Create(configFilePath) 420 c.Assert(err, checker.IsNil) 421 daemonConfig = `{"max-concurrent-downloads":1,"labels":["bar=foo"], "shutdown-timeout": 10}` 422 fmt.Fprintf(configFile, "%s", daemonConfig) 423 configFile.Close() 424 425 syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) 426 427 time.Sleep(3 * time.Second) 428 429 out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c)) 430 c.Assert(err, checker.IsNil) 431 432 c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, default-runtime=runc, insecure-registries=[], labels=[\"bar=foo\"], live-restore=false, max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s, runtimes=runc:{docker-runc []}, shutdown-timeout=10)", daemonID, daemonName)) 433 } 434 435 func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) { 436 testRequires(c, SameHostDaemon, DaemonIsLinux) 437 438 // daemon config file 439 configFilePath := "test.json" 440 configFile, err := os.Create(configFilePath) 441 c.Assert(err, checker.IsNil) 442 defer os.Remove(configFilePath) 443 444 daemonConfig := `{"labels":["foo=bar"]}` 445 fmt.Fprintf(configFile, "%s", daemonConfig) 446 configFile.Close() 447 c.Assert(s.d.Start(fmt.Sprintf("--config-file=%s", configFilePath)), check.IsNil) 448 449 // Get daemon ID 450 out, err := s.d.Cmd("info") 451 c.Assert(err, checker.IsNil) 452 daemonID := "" 453 daemonName := "" 454 for _, line := range strings.Split(out, "\n") { 455 if strings.HasPrefix(line, "ID: ") { 456 daemonID = strings.TrimPrefix(line, "ID: ") 457 } else if strings.HasPrefix(line, "Name: ") { 458 daemonName = strings.TrimPrefix(line, "Name: ") 459 } 460 } 461 c.Assert(daemonID, checker.Not(checker.Equals), "") 462 463 syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) 464 465 time.Sleep(3 * time.Second) 466 467 out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("daemon=%s", daemonID)) 468 c.Assert(err, checker.IsNil) 469 c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID)) 470 471 out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("daemon=%s", daemonName)) 472 c.Assert(err, checker.IsNil) 473 c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID)) 474 475 out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "daemon=foo") 476 c.Assert(err, checker.IsNil) 477 c.Assert(out, checker.Not(checker.Contains), fmt.Sprintf("daemon reload %s", daemonID)) 478 479 out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "type=daemon") 480 c.Assert(err, checker.IsNil) 481 c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s", daemonID)) 482 483 out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c), "--filter", "type=container") 484 c.Assert(err, checker.IsNil) 485 c.Assert(out, checker.Not(checker.Contains), fmt.Sprintf("daemon reload %s", daemonID)) 486 }