github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/logs_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "time" 8 9 . "github.com/containers/podman/v5/test/utils" 10 "github.com/containers/storage/pkg/stringid" 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 "github.com/onsi/gomega/format" 14 . "github.com/onsi/gomega/gexec" 15 ) 16 17 func isEventBackendJournald(podmanTest *PodmanTestIntegration) bool { 18 if !podmanTest.RemoteTest { 19 // If not remote test, '--events-backend' is set to 'file' or 'none' 20 return false 21 } 22 info := podmanTest.Podman([]string{"info", "--format", "{{.Host.EventLogger}}"}) 23 info.WaitWithDefaultTimeout() 24 return info.OutputToString() == "journald" 25 } 26 27 var _ = Describe("Podman logs", func() { 28 29 It("podman logs on not existent container", func() { 30 results := podmanTest.Podman([]string{"logs", "notexist"}) 31 results.WaitWithDefaultTimeout() 32 Expect(results).To(ExitWithError(125, `no container with name or ID "notexist" found: no such container`)) 33 }) 34 35 for _, log := range []string{"k8s-file", "journald", "json-file"} { 36 // This is important to move the 'log' var to the correct scope under Ginkgo flow. 37 log := log 38 39 // Flake prevention: journalctl makes no timeliness guarantees 40 logTimeout := time.Millisecond 41 if log == "journald" { 42 logTimeout = time.Second 43 } 44 45 skipIfJournaldInContainer := func() { 46 if log == "journald" { 47 SkipIfJournaldUnavailable() 48 } 49 } 50 51 It("all lines: "+log, func() { 52 skipIfJournaldInContainer() 53 54 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 55 logc.WaitWithDefaultTimeout() 56 Expect(logc).To(ExitCleanly()) 57 cid := logc.OutputToString() 58 59 results := podmanTest.Podman([]string{"wait", cid}) 60 results.WaitWithDefaultTimeout() 61 Expect(results).To(ExitCleanly()) 62 63 Eventually(func(g Gomega) { 64 results = podmanTest.Podman([]string{"logs", cid}) 65 results.WaitWithDefaultTimeout() 66 g.Expect(results).To(ExitCleanly()) 67 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 68 g.Expect(results.OutputToString()).To(Equal("podman podman podman")) 69 }).WithTimeout(logTimeout).Should(Succeed()) 70 }) 71 72 It("tail two lines: "+log, func() { 73 skipIfJournaldInContainer() 74 75 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 76 logc.WaitWithDefaultTimeout() 77 Expect(logc).To(ExitCleanly()) 78 cid := logc.OutputToString() 79 80 wait := podmanTest.Podman([]string{"wait", cid}) 81 wait.WaitWithDefaultTimeout() 82 Expect(wait).To(ExitCleanly()) 83 84 Eventually(func(g Gomega) { 85 results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) 86 results.WaitWithDefaultTimeout() 87 g.Expect(results).To(ExitCleanly()) 88 g.Expect(results.OutputToStringArray()).To(HaveLen(2)) 89 g.Expect(results.OutputToString()).To(Equal("podman podman")) 90 }).WithTimeout(logTimeout).Should(Succeed()) 91 }) 92 93 It("tail zero lines: "+log, func() { 94 skipIfJournaldInContainer() 95 96 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 97 logc.WaitWithDefaultTimeout() 98 Expect(logc).To(ExitCleanly()) 99 cid := logc.OutputToString() 100 101 wait := podmanTest.Podman([]string{"wait", cid}) 102 wait.WaitWithDefaultTimeout() 103 Expect(wait).To(ExitCleanly()) 104 105 time.Sleep(logTimeout) 106 results := podmanTest.Podman([]string{"logs", "--tail", "0", cid}) 107 results.WaitWithDefaultTimeout() 108 Expect(results).To(ExitCleanly()) 109 Expect(results.OutputToStringArray()).To(BeEmpty()) 110 }) 111 112 It("tail 99 lines: "+log, func() { 113 skipIfJournaldInContainer() 114 115 name := "test1" 116 logc := podmanTest.Podman([]string{"run", "--name", name, "--log-driver", log, ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 117 logc.WaitWithDefaultTimeout() 118 Expect(logc).To(ExitCleanly()) 119 120 wait := podmanTest.Podman([]string{"wait", name}) 121 wait.WaitWithDefaultTimeout() 122 Expect(wait).To(ExitCleanly()) 123 124 Eventually(func(g Gomega) { 125 results := podmanTest.Podman([]string{"logs", "--tail", "99", name}) 126 results.WaitWithDefaultTimeout() 127 g.Expect(results).To(ExitCleanly()) 128 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 129 }).WithTimeout(logTimeout).Should(Succeed()) 130 }) 131 132 It("tail 800 lines: "+log, func() { 133 skipIfJournaldInContainer() 134 135 // we match 800 line array here, make sure to print all lines when assertion fails. 136 // There is something weird going on (https://github.com/containers/podman/issues/18501) 137 // and only the normal output log does not seem to be enough to figure out why it flakes. 138 oldLength := format.MaxLength 139 // unlimited matcher output 140 format.MaxLength = 0 141 defer func() { 142 format.MaxLength = oldLength 143 }() 144 145 // this uses -d so that we do not have 1000 unnecessary lines printed in every test log 146 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-d", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"}) 147 logc.WaitWithDefaultTimeout() 148 Expect(logc).To(ExitCleanly()) 149 cid := logc.OutputToString() 150 151 // make sure we wait for the container to finish writing its output 152 wait := podmanTest.Podman([]string{"wait", cid}) 153 wait.WaitWithDefaultTimeout() 154 Expect(wait).To(ExitCleanly()) 155 156 Eventually(func(g Gomega) { 157 results := podmanTest.Podman([]string{"logs", "--tail", "800", cid}) 158 results.WaitWithDefaultTimeout() 159 g.Expect(results).To(ExitCleanly()) 160 g.Expect(results.OutputToStringArray()).To(HaveLen(800)) 161 }).WithTimeout(logTimeout).Should(Succeed()) 162 }) 163 164 It("tail 2 lines with timestamps: "+log, func() { 165 skipIfJournaldInContainer() 166 167 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 168 logc.WaitWithDefaultTimeout() 169 Expect(logc).To(ExitCleanly()) 170 cid := logc.OutputToString() 171 172 wait := podmanTest.Podman([]string{"wait", cid}) 173 wait.WaitWithDefaultTimeout() 174 Expect(wait).To(ExitCleanly()) 175 176 Eventually(func(g Gomega) { 177 results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) 178 results.WaitWithDefaultTimeout() 179 g.Expect(results).To(ExitCleanly()) 180 g.Expect(results.OutputToStringArray()).To(HaveLen(2)) 181 }).WithTimeout(logTimeout).Should(Succeed()) 182 }) 183 184 It("since time 2017-08-07: "+log, func() { 185 skipIfJournaldInContainer() 186 187 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 188 logc.WaitWithDefaultTimeout() 189 Expect(logc).To(ExitCleanly()) 190 cid := logc.OutputToString() 191 192 wait := podmanTest.Podman([]string{"wait", cid}) 193 wait.WaitWithDefaultTimeout() 194 Expect(wait).To(ExitCleanly()) 195 196 Eventually(func(g Gomega) { 197 results := podmanTest.Podman([]string{"logs", "--since", "2017-08-07T10:10:09.056611202-04:00", cid}) 198 results.WaitWithDefaultTimeout() 199 g.Expect(results).To(ExitCleanly()) 200 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 201 }).WithTimeout(logTimeout).Should(Succeed()) 202 }) 203 204 It("since duration 10m: "+log, func() { 205 skipIfJournaldInContainer() 206 207 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 208 logc.WaitWithDefaultTimeout() 209 Expect(logc).To(ExitCleanly()) 210 cid := logc.OutputToString() 211 212 wait := podmanTest.Podman([]string{"wait", cid}) 213 wait.WaitWithDefaultTimeout() 214 Expect(wait).To(ExitCleanly()) 215 216 Eventually(func(g Gomega) { 217 results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) 218 results.WaitWithDefaultTimeout() 219 g.Expect(results).To(ExitCleanly()) 220 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 221 }).WithTimeout(logTimeout).Should(Succeed()) 222 }) 223 224 It("until duration 10m: "+log, func() { 225 skipIfJournaldInContainer() 226 227 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 228 logc.WaitWithDefaultTimeout() 229 Expect(logc).To(ExitCleanly()) 230 cid := logc.OutputToString() 231 232 wait := podmanTest.Podman([]string{"wait", cid}) 233 wait.WaitWithDefaultTimeout() 234 Expect(wait).To(ExitCleanly()) 235 236 Eventually(func(g Gomega) { 237 results := podmanTest.Podman([]string{"logs", "--until", "10m", cid}) 238 results.WaitWithDefaultTimeout() 239 g.Expect(results).To(ExitCleanly()) 240 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 241 }).WithTimeout(logTimeout).Should(Succeed()) 242 }) 243 244 It("until time NOW: "+log, func() { 245 skipIfJournaldInContainer() 246 247 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 248 logc.WaitWithDefaultTimeout() 249 Expect(logc).To(ExitCleanly()) 250 cid := logc.OutputToString() 251 252 wait := podmanTest.Podman([]string{"wait", cid}) 253 wait.WaitWithDefaultTimeout() 254 Expect(wait).To(ExitCleanly()) 255 256 Eventually(func(g Gomega) { 257 now := time.Now() 258 now = now.Add(time.Minute * 1) 259 nowS := now.Format(time.RFC3339) 260 results := podmanTest.Podman([]string{"logs", "--until", nowS, cid}) 261 results.WaitWithDefaultTimeout() 262 g.Expect(results).To(ExitCleanly()) 263 g.Expect(results.OutputToStringArray()).To(HaveLen(3)) 264 }).WithTimeout(logTimeout).Should(Succeed()) 265 }) 266 267 It("latest and container name should fail: "+log, func() { 268 skipIfJournaldInContainer() 269 270 results := podmanTest.Podman([]string{"logs", "-l", "foobar"}) 271 results.WaitWithDefaultTimeout() 272 if IsRemote() { 273 Expect(results).To(ExitWithError(125, "unknown shorthand flag: 'l' in -l")) 274 } else { 275 Expect(results).To(ExitWithError(125, "--latest and containers cannot be used together")) 276 } 277 }) 278 279 It("two containers showing short container IDs: "+log, func() { 280 skipIfJournaldInContainer() 281 SkipIfRemote("podman-remote logs does not support showing two containers at the same time") 282 283 log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 284 log1.WaitWithDefaultTimeout() 285 Expect(log1).Should(ExitCleanly()) 286 cid1 := log1.OutputToString() 287 288 log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) 289 log2.WaitWithDefaultTimeout() 290 Expect(log2).Should(ExitCleanly()) 291 cid2 := log2.OutputToString() 292 293 wait := podmanTest.Podman([]string{"wait", cid1, cid2}) 294 wait.WaitWithDefaultTimeout() 295 Expect(wait).To(ExitCleanly()) 296 297 results := podmanTest.Podman([]string{"logs", cid1, cid2}) 298 results.WaitWithDefaultTimeout() 299 Expect(results).Should(ExitCleanly()) 300 301 output := results.OutputToStringArray() 302 Expect(output).To(HaveLen(6)) 303 Expect(output[0]).To(Or(ContainSubstring(cid1[:12]), ContainSubstring(cid2[:12]))) 304 }) 305 306 It("podman logs on a created container should result in 0 exit code: "+log, func() { 307 skipIfJournaldInContainer() 308 309 session := podmanTest.Podman([]string{"create", "--log-driver", log, "--name", "log", ALPINE}) 310 session.WaitWithDefaultTimeout() 311 Expect(session).To(ExitCleanly()) 312 313 results := podmanTest.Podman([]string{"logs", "log"}) 314 results.WaitWithDefaultTimeout() 315 Expect(results).To(ExitCleanly()) 316 }) 317 318 It("streaming output: "+log, func() { 319 skipIfJournaldInContainer() 320 321 containerName := "logs-f" 322 323 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-dt", ALPINE, "sh", "-c", "echo podman-1; sleep 1; echo podman-2"}) 324 logc.WaitWithDefaultTimeout() 325 Expect(logc).To(ExitCleanly()) 326 327 results := podmanTest.Podman([]string{"logs", "-f", containerName}) 328 results.WaitWithDefaultTimeout() 329 330 if log == "journald" && !isEventBackendJournald(podmanTest) { 331 // --follow + journald log-driver is only supported with journald events-backend(PR #10431) 332 Expect(results).To(ExitWithError(125, "using --follow with the journald --log-driver but without the journald --events-backend")) 333 return 334 } 335 336 Expect(results).To(ExitCleanly()) 337 338 Expect(results.OutputToString()).To(ContainSubstring("podman-1")) 339 Expect(results.OutputToString()).To(ContainSubstring("podman-2")) 340 341 // Container should now be terminatING or terminatED, but we 342 // have no guarantee of which: 'logs -f' does not necessarily 343 // wait for cleanup. Run 'inspect' and accept either state. 344 inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Status}}", containerName}) 345 inspect.WaitWithDefaultTimeout() 346 if inspect.ExitCode() == 0 { 347 Expect(inspect.OutputToString()).To(Equal("exited")) 348 // TODO: add 2-second wait loop to confirm cleanup 349 } else { 350 Expect(inspect.ErrorToString()).To(ContainSubstring("no such container")) 351 } 352 353 results = podmanTest.Podman([]string{"rm", "--time", "0", "-f", containerName}) 354 results.WaitWithDefaultTimeout() 355 Expect(results).To(ExitCleanly()) 356 }) 357 358 It("follow output stopped container: "+log, func() { 359 skipIfJournaldInContainer() 360 361 containerName := "logs-f" 362 363 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, ALPINE, "true"}) 364 logc.WaitWithDefaultTimeout() 365 Expect(logc).To(ExitCleanly()) 366 367 results := podmanTest.Podman([]string{"logs", "-f", containerName}) 368 results.WaitWithDefaultTimeout() 369 if log == "journald" && !isEventBackendJournald(podmanTest) { 370 // --follow + journald log-driver is only supported with journald events-backend(PR #10431) 371 Expect(results).To(ExitWithError(125, "using --follow with the journald --log-driver but without the journald --events-backend")) 372 return 373 } 374 Expect(results).To(ExitCleanly()) 375 }) 376 377 It("using container with container log-size: "+log, func() { 378 skipIfJournaldInContainer() 379 380 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--log-opt=max-size=10k", "-d", ALPINE, "echo", "podman podman podman"}) 381 logc.WaitWithDefaultTimeout() 382 Expect(logc).To(ExitCleanly()) 383 cid := logc.OutputToString() 384 385 wait := podmanTest.Podman([]string{"wait", cid}) 386 wait.WaitWithDefaultTimeout() 387 Expect(wait).To(ExitCleanly()) 388 389 inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.HostConfig.LogConfig.Size}}", cid}) 390 inspect.WaitWithDefaultTimeout() 391 Expect(inspect).To(ExitCleanly()) 392 Expect(inspect.OutputToString()).To(Equal("10kB")) 393 394 Eventually(func(g Gomega) { 395 results := podmanTest.Podman([]string{"logs", cid}) 396 results.WaitWithDefaultTimeout() 397 g.Expect(results).To(ExitCleanly()) 398 g.Expect(results.OutputToString()).To(Equal("podman podman podman")) 399 }).WithTimeout(logTimeout).Should(Succeed()) 400 }) 401 402 It("Make sure logs match expected length: "+log, func() { 403 skipIfJournaldInContainer() 404 405 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"}) 406 logc.WaitWithDefaultTimeout() 407 Expect(logc).To(ExitCleanly()) 408 409 wait := podmanTest.Podman([]string{"wait", "test"}) 410 wait.WaitWithDefaultTimeout() 411 Expect(wait).To(ExitCleanly()) 412 413 Eventually(func(g Gomega) { 414 results := podmanTest.Podman([]string{"logs", "test"}) 415 results.WaitWithDefaultTimeout() 416 g.Expect(results).To(ExitCleanly()) 417 outlines := results.OutputToStringArray() 418 g.Expect(outlines).To(HaveLen(2)) 419 g.Expect(outlines[0]).To(Equal("1")) 420 g.Expect(outlines[1]).To(Equal("2")) 421 }).WithTimeout(logTimeout).Should(Succeed()) 422 }) 423 424 It("podman logs test stdout and stderr: "+log, func() { 425 skipIfJournaldInContainer() 426 427 cname := "log-test" 428 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"}) 429 logc.WaitWithDefaultTimeout() 430 Expect(logc).To(Exit(0)) 431 432 wait := podmanTest.Podman([]string{"wait", cname}) 433 wait.WaitWithDefaultTimeout() 434 Expect(wait).To(ExitCleanly()) 435 436 Eventually(func(g Gomega) { 437 results := podmanTest.Podman([]string{"logs", cname}) 438 results.WaitWithDefaultTimeout() 439 g.Expect(results).To(Exit(0)) 440 g.Expect(results.OutputToString()).To(Equal("stdout")) 441 g.Expect(results.ErrorToString()).To(Equal("stderr")) 442 }).WithTimeout(logTimeout).Should(Succeed()) 443 }) 444 445 It("podman logs partial log lines: "+log, func() { 446 skipIfJournaldInContainer() 447 448 cname := "log-test" 449 content := stringid.GenerateRandomID() 450 // use printf to print no extra newline 451 logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "printf", content}) 452 logc.WaitWithDefaultTimeout() 453 Expect(logc).To(ExitCleanly()) 454 // Important: do not use OutputToString(), this will remove the trailing newline from the output. 455 // However this test must make sure that there is no such extra newline. 456 Expect(string(logc.Out.Contents())).To(Equal(content)) 457 458 Eventually(func(g Gomega) { 459 logs := podmanTest.Podman([]string{"logs", cname}) 460 logs.WaitWithDefaultTimeout() 461 g.Expect(logs).To(ExitCleanly()) 462 // see comment above 463 g.Expect(string(logs.Out.Contents())).To(Equal(content)) 464 }).WithTimeout(logTimeout).Should(Succeed()) 465 }) 466 467 It("podman pod logs -l with newer container created: "+log, func() { 468 skipIfJournaldInContainer() 469 SkipIfRemote("no -l in remote") 470 471 podName := "testPod" 472 containerName1 := "container1" 473 containerName2 := "container2" 474 containerName3 := "container3" 475 476 testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)}) 477 testPod.WaitWithDefaultTimeout() 478 Expect(testPod).To(ExitCleanly()) 479 480 log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName1, "--pod", podName, BB, "echo", "log1"}) 481 log1.WaitWithDefaultTimeout() 482 Expect(log1).To(ExitCleanly()) 483 484 log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName2, "--pod", podName, BB, "echo", "log2"}) 485 log2.WaitWithDefaultTimeout() 486 Expect(log2).To(ExitCleanly()) 487 488 ctr := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName3, BB, "date"}) 489 ctr.WaitWithDefaultTimeout() 490 Expect(ctr).To(ExitCleanly()) 491 492 Eventually(func(g Gomega) { 493 results := podmanTest.Podman([]string{"pod", "logs", "-l"}) 494 results.WaitWithDefaultTimeout() 495 g.Expect(results).To(ExitCleanly()) 496 podOutput := results.OutputToString() 497 498 results = podmanTest.Podman([]string{"logs", "-l"}) 499 results.WaitWithDefaultTimeout() 500 g.Expect(results).To(ExitCleanly()) 501 ctrOutput := results.OutputToString() 502 503 g.Expect(podOutput).ToNot(Equal(ctrOutput)) 504 }).WithTimeout(logTimeout).Should(Succeed()) 505 }) 506 507 It("podman pod logs -l: "+log, func() { 508 skipIfJournaldInContainer() 509 SkipIfRemote("no -l in remote") 510 511 podName := "testPod" 512 containerName1 := "container1" 513 containerName2 := "container2" 514 515 testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)}) 516 testPod.WaitWithDefaultTimeout() 517 Expect(testPod).To(ExitCleanly()) 518 519 log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName1, "--pod", podName, BB, "echo", "log1"}) 520 log1.WaitWithDefaultTimeout() 521 Expect(log1).To(ExitCleanly()) 522 523 log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName2, "--pod", podName, BB, "echo", "log2"}) 524 log2.WaitWithDefaultTimeout() 525 Expect(log2).To(ExitCleanly()) 526 527 Eventually(func(g Gomega) { 528 results := podmanTest.Podman([]string{"pod", "logs", "-l"}) 529 results.WaitWithDefaultTimeout() 530 g.Expect(results).To(ExitCleanly()) 531 output := results.OutputToString() 532 g.Expect(output).To(ContainSubstring("log1")) 533 g.Expect(output).To(ContainSubstring("log2")) 534 }).WithTimeout(logTimeout).Should(Succeed()) 535 }) 536 } 537 538 It("using journald for container with container tag", func() { 539 SkipIfJournaldUnavailable() 540 logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "--log-opt=tag={{.ImageName}},withcomma", "-d", ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"}) 541 logc.WaitWithDefaultTimeout() 542 Expect(logc).To(ExitCleanly()) 543 cid := logc.OutputToString() 544 545 wait := podmanTest.Podman([]string{"wait", cid}) 546 wait.WaitWithDefaultTimeout() 547 Expect(wait).To(ExitCleanly()) 548 549 Eventually(func(g Gomega) { 550 cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_TAG", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid)) 551 out, err := cmd.CombinedOutput() 552 g.Expect(err).ToNot(HaveOccurred()) 553 g.Expect(string(out)).To(ContainSubstring(ALPINE + ",withcomma")) 554 }).Should(Succeed()) 555 }) 556 557 It("using journald container name", func() { 558 SkipIfJournaldUnavailable() 559 containerName := "inside-journal" 560 logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-d", "--name", containerName, ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"}) 561 logc.WaitWithDefaultTimeout() 562 Expect(logc).To(ExitCleanly()) 563 cid := logc.OutputToString() 564 565 wait := podmanTest.Podman([]string{"wait", cid}) 566 wait.WaitWithDefaultTimeout() 567 Expect(wait).To(ExitCleanly()) 568 569 Eventually(func(g Gomega) { 570 cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_NAME", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid)) 571 out, err := cmd.CombinedOutput() 572 g.Expect(err).ToNot(HaveOccurred()) 573 g.Expect(string(out)).To(ContainSubstring(containerName)) 574 }).Should(Succeed()) 575 }) 576 577 It("podman logs with log-driver=none errors", func() { 578 ctrName := "logsctr" 579 logc := podmanTest.Podman([]string{"run", "--name", ctrName, "-d", "--log-driver", "none", ALPINE, "top"}) 580 logc.WaitWithDefaultTimeout() 581 Expect(logc).To(ExitCleanly()) 582 583 logs := podmanTest.Podman([]string{"logs", "-f", ctrName}) 584 logs.WaitWithDefaultTimeout() 585 Expect(logs).To(ExitWithError(125, "this container is using the 'none' log driver, cannot read logs: this container is not logging output")) 586 }) 587 588 It("podman logs with non ASCII log tag fails without correct LANG", func() { 589 SkipIfJournaldUnavailable() 590 // need to set the LANG to something that does not support german umlaute to trigger the failure case 591 cleanup := setLangEnv("C") 592 if IsRemote() { 593 podmanTest.RestartRemoteService() 594 } 595 defer cleanup() 596 logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "--log-opt", "tag=äöüß", ALPINE, "echo", "podman"}) 597 logc.WaitWithDefaultTimeout() 598 Expect(logc).To(ExitWithError(126, "conmon failed: exit status 1")) 599 if !IsRemote() { 600 Expect(logc.ErrorToString()).To(ContainSubstring("conmon: option parsing failed: Invalid byte sequence in conversion input")) 601 } 602 }) 603 604 It("podman logs with non ASCII log tag succeeds with proper env", func() { 605 SkipIfJournaldUnavailable() 606 cleanup := setLangEnv("en_US.UTF-8") 607 if IsRemote() { 608 podmanTest.RestartRemoteService() 609 } 610 defer cleanup() 611 logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "--log-opt", "tag=äöüß", ALPINE, "echo", "podman"}) 612 logc.WaitWithDefaultTimeout() 613 Expect(logc).To(ExitCleanly()) 614 Expect(logc.OutputToString()).To(Equal("podman")) 615 }) 616 617 It("podman pod logs with container names", func() { 618 SkipIfRemote("Remote can only process one container at a time") 619 podName := "testPod" 620 containerName1 := "container1" 621 containerName2 := "container2" 622 623 testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)}) 624 testPod.WaitWithDefaultTimeout() 625 Expect(testPod).To(ExitCleanly()) 626 627 log1 := podmanTest.Podman([]string{"run", "--name", containerName1, "--pod", podName, BB, "echo", "log1"}) 628 log1.WaitWithDefaultTimeout() 629 Expect(log1).To(ExitCleanly()) 630 631 log2 := podmanTest.Podman([]string{"run", "--name", containerName2, "--pod", podName, BB, "echo", "log2"}) 632 log2.WaitWithDefaultTimeout() 633 Expect(log2).To(ExitCleanly()) 634 635 Eventually(func(g Gomega) { 636 results := podmanTest.Podman([]string{"pod", "logs", "--names", podName}) 637 results.WaitWithDefaultTimeout() 638 g.Expect(results).To(ExitCleanly()) 639 640 output := results.OutputToStringArray() 641 g.Expect(output).To(HaveLen(2)) 642 g.Expect(output).To(ContainElement(ContainSubstring(containerName1))) 643 g.Expect(output).To(ContainElement(ContainSubstring(containerName2))) 644 }).Should(Succeed()) 645 }) 646 It("podman pod logs with different colors", func() { 647 SkipIfRemote("Remote can only process one container at a time") 648 podName := "testPod" 649 containerName1 := "container1" 650 containerName2 := "container2" 651 testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)}) 652 testPod.WaitWithDefaultTimeout() 653 Expect(testPod).To(ExitCleanly()) 654 log1 := podmanTest.Podman([]string{"run", "--name", containerName1, "--pod", podName, BB, "echo", "log1"}) 655 log1.WaitWithDefaultTimeout() 656 Expect(log1).To(ExitCleanly()) 657 log2 := podmanTest.Podman([]string{"run", "--name", containerName2, "--pod", podName, BB, "echo", "log2"}) 658 log2.WaitWithDefaultTimeout() 659 Expect(log2).To(ExitCleanly()) 660 661 Eventually(func(g Gomega) { 662 results := podmanTest.Podman([]string{"pod", "logs", "--color", podName}) 663 results.WaitWithDefaultTimeout() 664 g.Expect(results).To(ExitCleanly()) 665 output := results.OutputToStringArray() 666 g.Expect(output).To(HaveLen(2)) 667 g.Expect(output[0]).To(MatchRegexp(`\x1b\[3[0-9a-z ]+\x1b\[0m`)) 668 g.Expect(output[1]).To(MatchRegexp(`\x1b\[3[0-9a-z ]+\x1b\[0m`)) 669 }).Should(Succeed()) 670 }) 671 }) 672 673 func setLangEnv(lang string) func() { 674 oldLang, okLang := os.LookupEnv("LANG") 675 oldLcAll, okLc := os.LookupEnv("LC_ALL") 676 err := os.Setenv("LANG", lang) 677 Expect(err).ToNot(HaveOccurred()) 678 err = os.Setenv("LC_ALL", "") 679 Expect(err).ToNot(HaveOccurred()) 680 681 return func() { 682 if okLang { 683 os.Setenv("LANG", oldLang) 684 } else { 685 os.Unsetenv("LANG") 686 } 687 if okLc { 688 os.Setenv("LC_ALL", oldLcAll) 689 } else { 690 os.Unsetenv("LC_ALL") 691 } 692 } 693 }