github.com/containers/podman/v5@v5.1.0-rc1/test/system/252-quadlet.bats (about) 1 #!/usr/bin/env bats -*- bats -*- 2 # 3 # Tests generated configurations for systemd. 4 # 5 6 load helpers 7 load helpers.network 8 load helpers.registry 9 load helpers.systemd 10 11 UNIT_FILES=() 12 13 function start_time() { 14 sleep_to_next_second # Ensure we're on a new second with no previous logging 15 STARTED_TIME=$(date "+%F %R:%S") # Start time for new log time 16 } 17 18 function setup() { 19 skip_if_remote "quadlet tests are meaningless over remote" 20 skip_if_rootless_cgroupsv1 "Can't use --cgroups=split w/ CGv1 (issue 17456, wontfix)" 21 skip_if_journald_unavailable "Needed for RHEL. FIXME: we might be able to re-enable a subset of tests." 22 23 test -x "$QUADLET" || die "Cannot run quadlet tests without executable \$QUADLET ($QUADLET)" 24 25 start_time 26 27 basic_setup 28 } 29 30 function teardown() { 31 for UNIT_FILE in ${UNIT_FILES[@]}; do 32 if [[ -e "$UNIT_FILE" ]]; then 33 local service=$(basename "$UNIT_FILE") 34 run systemctl stop "$service" 35 if [ $status -ne 0 ]; then 36 echo "# WARNING: systemctl stop failed in teardown: $output" >&3 37 fi 38 rm -f "$UNIT_FILE" 39 fi 40 done 41 systemctl daemon-reload 42 43 basic_teardown 44 } 45 46 # Converts the quadlet file and installs the result it in $UNIT_DIR 47 function run_quadlet() { 48 local sourcefile="$1" 49 local service=$(quadlet_to_service_name "$sourcefile") 50 51 # quadlet always works on an entire directory, so copy the file 52 # to transform to the given or newly created tmpdir 53 local quadlet_tmpdir="$2" 54 if [ -z "$quadlet_tmpdir" ]; then 55 quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX) 56 fi 57 cp $sourcefile $quadlet_tmpdir/ 58 59 echo "$_LOG_PROMPT $QUADLET $_DASHUSER $UNIT_DIR" 60 QUADLET_UNIT_DIRS="$quadlet_tmpdir" run \ 61 timeout --foreground -v --kill=10 $PODMAN_TIMEOUT \ 62 $QUADLET $_DASHUSER $UNIT_DIR 63 echo "$output" 64 assert $status -eq 0 "Failed to convert quadlet file: $sourcefile" 65 is "$output" "" "quadlet should report no errors" 66 67 # Ensure this is teared down 68 UNIT_FILES+=("$UNIT_DIR/$service") 69 70 QUADLET_SERVICE_NAME="$service" 71 QUADLET_SYSLOG_ID="$(basename $service .service)" 72 QUADLET_CONTAINER_NAME="systemd-$QUADLET_SYSLOG_ID" 73 74 cat $UNIT_DIR/$QUADLET_SERVICE_NAME 75 } 76 77 function service_setup() { 78 local service="$1" 79 local option="$2" 80 81 systemctl daemon-reload 82 83 local startargs="" 84 local statusexit=0 85 local activestate="active" 86 87 # If option wait, start and wait for service to exist 88 if [ "$option" == "wait" ]; then 89 startargs="--wait" 90 statusexit=3 91 local activestate="inactive" 92 fi 93 94 systemctl_start $startargs "$service" 95 96 # FIXME FIXME FIXME: this is racy with short-lived containers! 97 echo "$_LOG_PROMPT systemctl status $service" 98 run systemctl status "$service" 99 echo "$output" 100 assert $status -eq $statusexit "systemctl status $service" 101 102 echo "$_LOG_PROMPT systemctl show --value --property=ActiveState $service" 103 run systemctl show --value --property=ActiveState "$service" 104 echo "$output" 105 assert $status -eq 0 "systemctl show $service" 106 is "$output" $activestate 107 } 108 109 # Helper to stop a systemd service running a container 110 function service_cleanup() { 111 local service="$1" 112 local expected_state="$2" 113 114 run systemctl stop "$service" 115 assert $status -eq 0 "Error stopping systemd unit $service: $output" 116 117 # Regression test for #11304: confirm that unit stops into correct state 118 if [[ -n "$expected_state" ]]; then 119 run systemctl show --property=ActiveState "$service" 120 assert "$output" = "ActiveState=$expected_state" \ 121 "state of service $service after systemctl stop" 122 fi 123 124 rm -f "$UNIT_DIR/$service" 125 systemctl daemon-reload 126 } 127 128 function create_secret() { 129 local secret_name=$(random_string) 130 local secret_file=$PODMAN_TMPDIR/secret_$(random_string) 131 local secret=$(random_string) 132 133 echo $secret > $secret_file 134 run_podman secret create $secret_name $secret_file 135 136 SECRET_NAME=$secret_name 137 SECRET=$secret 138 } 139 140 function remove_secret() { 141 local secret_name="$1" 142 143 run_podman secret rm $secret_name 144 } 145 146 @test "quadlet - basic" { 147 # Network=none is to work around a Pasta bug, can be removed once a patched Pasta is available. 148 # Ref https://github.com/containers/podman/pull/21563#issuecomment-1965145324 149 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 150 cat > $quadlet_file <<EOF 151 [Container] 152 Image=$IMAGE 153 Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; sleep inf" 154 Notify=yes 155 LogDriver=passthrough 156 Network=none 157 EOF 158 159 # FIXME: Temporary until podman fully removes cgroupsv1 support; see #21431 160 if [[ -n "$PODMAN_IGNORE_CGROUPSV1_WARNING" ]]; then 161 skip "Way too complicated to test under cgroupsv1, and not worth the effort" 162 fi 163 164 run_quadlet "$quadlet_file" 165 service_setup $QUADLET_SERVICE_NAME 166 167 # Check that we can read the logs from the container with podman logs even 168 # with the `passthrough` driver. The log may need a short period of time 169 # to bubble up into the journal logs, so wait for it. 170 wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME 171 # Make sure it's an *exact* match, not just a substring (i.e. no spurious 172 # warnings or other cruft). 173 run_podman logs $QUADLET_CONTAINER_NAME 174 assert "$output" == "STARTED CONTAINER" "exact/full match when using the 'passthrough' driver" 175 176 # Also look for the logs via `journalctl`. 177 run journalctl "--since=$STARTED_TIME" --unit="$QUADLET_SERVICE_NAME" 178 is "$output" '.*STARTED CONTAINER.*' 179 180 run_podman container inspect --format "{{.State.Status}}" $QUADLET_CONTAINER_NAME 181 is "$output" "running" "container should be started by systemd and hence be running" 182 183 service_cleanup $QUADLET_SERVICE_NAME failed 184 } 185 186 @test "quadlet conflict names" { 187 # If two directories in the search have files with the same name, quadlet should 188 # only process the first name 189 dir1=$PODMAN_TMPDIR/$(random_string) 190 dir2=$PODMAN_TMPDIR/$(random_string) 191 local quadlet_file=basic_$(random_string).container 192 mkdir -p $dir1 $dir2 193 194 cat > $dir1/$quadlet_file <<EOF 195 [Container] 196 Image=$IMAGE 197 Notify=yes 198 EOF 199 200 cat > $dir2/$quadlet_file <<EOF 201 [Container] 202 Image=$IMAGE 203 Notify=no 204 EOF 205 QUADLET_UNIT_DIRS="$dir1:$dir2" run \ 206 timeout --foreground -v --kill=10 $PODMAN_TIMEOUT \ 207 $QUADLET --dryrun 208 assert "$output" =~ "Notify=yes" "quadlet should show Notify=yes" 209 assert "$output" !~ "Notify=no" "quadlet should not show Notify=no" 210 } 211 212 @test "quadlet - envvar" { 213 local quadlet_file=$PODMAN_TMPDIR/envvar_$(random_string).container 214 cat > $quadlet_file <<EOF 215 [Container] 216 Image=$IMAGE 217 Exec=sh -c "echo OUTPUT: \"\$FOOBAR\" \"\$BAR\"" 218 Environment="FOOBAR=Foo Bar" BAR=bar 219 LogDriver=passthrough 220 EOF 221 222 run_quadlet "$quadlet_file" 223 service_setup $QUADLET_SERVICE_NAME wait 224 225 # Ensure we have the right output, sync is done via waiting for service to exit (service_setup wait) 226 227 # Note: Here we have to filter by syslog id instead of unit, because there is a (known) race 228 # condition where if the cgroup is cleaned up before journald sees the message, then the journal 229 # doesn't know the cgroup and thus not the unit. (See https://github.com/systemd/systemd/issues/2913) 230 run journalctl "--since=$STARTED_TIME" SYSLOG_IDENTIFIER="$QUADLET_SYSLOG_ID" 231 is "$output" '.*OUTPUT: Foo Bar bar.*' 232 233 service_cleanup $QUADLET_SERVICE_NAME inactive 234 } 235 236 @test "quadlet - ContainerName" { 237 local quadlet_file=$PODMAN_TMPDIR/containername_$(random_string).container 238 cat > $quadlet_file <<EOF 239 [Container] 240 ContainerName=customcontainername 241 Image=$IMAGE 242 Exec=top" 243 EOF 244 245 run_quadlet "$quadlet_file" 246 service_setup $QUADLET_SERVICE_NAME 247 248 # Ensure we can access with the custom container name 249 run_podman container inspect --format "{{.State.Status}}" customcontainername 250 is "$output" "running" "container should be started by systemd and hence be running" 251 252 service_cleanup $QUADLET_SERVICE_NAME failed 253 } 254 255 @test "quadlet - labels" { 256 local quadlet_file=$PODMAN_TMPDIR/labels_$(random_string).container 257 cat > $quadlet_file <<EOF 258 [Container] 259 Image=$IMAGE 260 Exec=top 261 Label="foo=foo bar" "key=val" 262 Annotation="afoo=afoo bar" 263 Annotation="akey=aval" 264 EOF 265 266 run_quadlet "$quadlet_file" 267 service_setup $QUADLET_SERVICE_NAME 268 269 run_podman container inspect --format "{{.Config.Labels.foo}}" $QUADLET_CONTAINER_NAME 270 is "$output" "foo bar" 271 run_podman container inspect --format "{{.Config.Labels.key}}" $QUADLET_CONTAINER_NAME 272 is "$output" "val" 273 run_podman container inspect --format "{{.Config.Annotations.afoo}}" $QUADLET_CONTAINER_NAME 274 is "$output" "afoo bar" 275 run_podman container inspect --format "{{.Config.Annotations.akey}}" $QUADLET_CONTAINER_NAME 276 is "$output" "aval" 277 278 service_cleanup $QUADLET_SERVICE_NAME failed 279 } 280 281 @test "quadlet - oneshot" { 282 local quadlet_file=$PODMAN_TMPDIR/oneshot_$(random_string).container 283 cat > $quadlet_file <<EOF 284 [Container] 285 Image=$IMAGE 286 Exec=echo INITIALIZED 287 288 [Service] 289 Type=oneshot 290 RemainAfterExit=yes 291 EOF 292 293 run_quadlet "$quadlet_file" 294 295 service_setup $QUADLET_SERVICE_NAME 296 297 # Ensure we have output. Output is synced by oneshot command exit 298 run journalctl "--since=$STARTED_TIME" SYSLOG_IDENTIFIER="$QUADLET_SYSLOG_ID" 299 is "$output" '.*INITIALIZED.*' 300 301 service_cleanup $QUADLET_SERVICE_NAME inactive 302 } 303 304 @test "quadlet - volume" { 305 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).volume 306 cat > $quadlet_file <<EOF 307 [Volume] 308 Label=foo=bar other="with space" 309 EOF 310 311 run_quadlet "$quadlet_file" 312 313 service_setup $QUADLET_SERVICE_NAME 314 315 local volume_name=systemd-$(basename $quadlet_file .volume) 316 run_podman volume ls 317 is "$output" ".*local.*${volume_name}.*" 318 319 run_podman volume inspect --format "{{.Labels.foo}}" $volume_name 320 is "$output" "bar" 321 run_podman volume inspect --format "{{.Labels.other}}" $volume_name 322 is "$output" "with space" 323 324 service_cleanup $QUADLET_SERVICE_NAME inactive 325 } 326 327 # A quadlet container depends on a quadlet volume 328 @test "quadlet - volume dependency" { 329 # Save the unit name to use as the volume for the container 330 local quadlet_vol_unit=dep_$(random_string).volume 331 local quadlet_vol_file=$PODMAN_TMPDIR/${quadlet_vol_unit} 332 cat > $quadlet_vol_file <<EOF 333 [Volume] 334 EOF 335 336 # Have quadlet create the systemd unit file for the volume unit 337 run_quadlet "$quadlet_vol_file" 338 339 # Save the volume service name since the variable will be overwritten 340 local vol_service=$QUADLET_SERVICE_NAME 341 local volume_name=systemd-$(basename $quadlet_vol_file .volume) 342 343 local quadlet_file=$PODMAN_TMPDIR/user_$(random_string).container 344 cat > $quadlet_file <<EOF 345 [Container] 346 Image=$IMAGE 347 Exec=top 348 Volume=$quadlet_vol_unit:/tmp 349 EOF 350 351 # Have quadlet create the systemd unit file for the container unit 352 run_quadlet "$quadlet_file" 353 354 # Save the container service name for readability 355 local container_service=$QUADLET_SERVICE_NAME 356 357 # Volume should not exist 358 run_podman 1 volume exists ${volume_name} 359 360 # Start the container service which should also trigger the start of the volume service 361 service_setup $container_service 362 363 # Volume system unit should be active 364 run systemctl show --property=ActiveState "$vol_service" 365 assert "$output" = "ActiveState=active" \ 366 "volume should be active via dependency" 367 368 # Volume should exist 369 run_podman volume exists ${volume_name} 370 371 # Shutdown the service and remove the volume 372 service_cleanup $container_service failed 373 run_podman volume rm $volume_name 374 } 375 376 # A quadlet container depends on a named quadlet volume 377 @test "quadlet - named volume dependency" { 378 # Save the unit name to use as the volume for the container 379 local quadlet_vol_unit=dep_$(random_string).volume 380 local quadlet_vol_file=$PODMAN_TMPDIR/${quadlet_vol_unit} 381 cat > $quadlet_vol_file <<EOF 382 [Volume] 383 VolumeName=foo 384 EOF 385 386 # Have quadlet create the systemd unit file for the volume unit 387 local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX) 388 run_quadlet "$quadlet_vol_file" "$quadlet_tmpdir" 389 390 # Save the volume service name since the variable will be overwritten 391 local vol_service=$QUADLET_SERVICE_NAME 392 local volume_name="foo" 393 394 local quadlet_file=$PODMAN_TMPDIR/user_$(random_string).container 395 cat > $quadlet_file <<EOF 396 [Container] 397 Image=$IMAGE 398 Exec=top 399 Volume=$quadlet_vol_unit:/tmp 400 EOF 401 402 # Have quadlet create the systemd unit file for the container unit 403 run_quadlet "$quadlet_file" "$quadlet_tmpdir" 404 405 # Save the container service name for readability 406 local container_service=$QUADLET_SERVICE_NAME 407 local container_name=systemd-$(basename $quadlet_file .container) 408 409 # Volume should not exist 410 run_podman 1 volume exists ${volume_name} 411 412 # Start the container service which should also trigger the start of the volume service 413 service_setup $container_service 414 415 # Volume system unit should be active 416 run systemctl show --property=ActiveState "$vol_service" 417 assert "$output" = "ActiveState=active" "volume should be active via dependency" 418 419 # Volume should exist 420 run_podman volume exists ${volume_name} 421 422 # Container should be attached to defined volume 423 run_podman container inspect --format "{{(index .Mounts 0).Name}}" $container_name 424 assert "$output" = "$volume_name" "container should be attached to network $volume_name" 425 426 # Shutdown the service and remove the volume 427 service_cleanup $container_service failed 428 run_podman volume rm $volume_name 429 } 430 431 @test "quadlet - network" { 432 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).network 433 cat > $quadlet_file <<EOF 434 [Network] 435 Label=foo=bar other="with space" 436 EOF 437 438 run_quadlet "$quadlet_file" 439 440 service_setup $QUADLET_SERVICE_NAME 441 442 local network_name=systemd-$(basename $quadlet_file .network) 443 run_podman network exists $network_name 444 445 run_podman network inspect --format "{{.Labels.foo}}" $network_name 446 is "$output" "bar" 447 run_podman network inspect --format "{{.Labels.other}}" $network_name 448 is "$output" "with space" 449 450 service_cleanup $QUADLET_SERVICE_NAME inactive 451 } 452 453 # A quadlet container depends on a quadlet network 454 @test "quadlet - network dependency" { 455 # Save the unit name to use as the network for the container 456 local quadlet_network_unit=dep_$(random_string).network 457 local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit} 458 cat > $quadlet_network_file <<EOF 459 [Network] 460 EOF 461 462 # Have quadlet create the systemd unit file for the network unit 463 run_quadlet "$quadlet_network_file" 464 465 # Save the volume service name since the variable will be overwritten 466 local network_service=$QUADLET_SERVICE_NAME 467 local network_name=systemd-$(basename $quadlet_network_file .network) 468 469 local quadlet_file=$PODMAN_TMPDIR/user_$(random_string).container 470 cat > $quadlet_file <<EOF 471 [Container] 472 Image=$IMAGE 473 Exec=top 474 Network=$quadlet_network_unit 475 EOF 476 477 run_quadlet "$quadlet_file" 478 479 # Save the container service name for readability 480 local container_service=$QUADLET_SERVICE_NAME 481 482 # Network should not exist 483 run_podman 1 network exists $network_name 484 485 service_setup $container_service 486 487 # Network system unit should be active 488 run systemctl show --property=ActiveState "$network_service" 489 assert "$output" = "ActiveState=active" \ 490 "network should be active via dependency" 491 492 # Network should exist 493 run_podman network exists $network_name 494 495 service_cleanup $QUADLET_SERVICE_NAME failed 496 run_podman network rm $network_name 497 } 498 499 # A quadlet container depends on a named quadlet network 500 @test "quadlet - named network dependency" { 501 # Save the unit name to use as the network for the container 502 local quadlet_network_unit=dep_$(random_string).network 503 local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit} 504 cat > $quadlet_network_file <<EOF 505 [Network] 506 NetworkName=foo 507 EOF 508 509 # Have quadlet create the systemd unit file for the network unit 510 local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX) 511 run_quadlet "$quadlet_network_file" "$quadlet_tmpdir" 512 513 # Save the network service name since the variable will be overwritten 514 local network_service=$QUADLET_SERVICE_NAME 515 local network_name="foo" 516 517 local quadlet_file=$PODMAN_TMPDIR/user_$(random_string).container 518 cat > $quadlet_file <<EOF 519 [Container] 520 Image=$IMAGE 521 Exec=top 522 Network=$quadlet_network_unit 523 EOF 524 525 run_quadlet "$quadlet_file" "$quadlet_tmpdir" 526 527 # Save the container service name for readability 528 local container_service=$QUADLET_SERVICE_NAME 529 local container_name=systemd-$(basename $quadlet_file .container) 530 531 # Network should not exist 532 run_podman 1 network exists $network_name 533 534 service_setup $container_service 535 536 # Network system unit should be active 537 run systemctl show --property=ActiveState "$network_service" 538 assert "$output" = "ActiveState=active" "network should be active via dependency" 539 540 # Network should exist 541 run_podman network exists $network_name 542 543 # Container should be attached to defined network 544 run_podman container inspect --format "{{index .NetworkSettings.Networks \"$network_name\"}}" $container_name 545 assert "$output" != "<nil>" "container should be attached to network $network_name" 546 547 service_cleanup $QUADLET_SERVICE_NAME failed 548 run_podman network rm $network_name 549 } 550 551 @test "quadlet kube - basic" { 552 # Create the YAMl file 553 pod_name="test_pod" 554 container_name="test" 555 yaml_source="$PODMAN_TMPDIR/basic_$(random_string).yaml" 556 cat >$yaml_source <<EOF 557 apiVersion: v1 558 kind: Pod 559 metadata: 560 labels: 561 app: test 562 name: $pod_name 563 spec: 564 containers: 565 - command: 566 - "sh" 567 args: 568 - "-c" 569 - "echo STARTED CONTAINER; top -b" 570 image: $IMAGE 571 name: $container_name 572 EOF 573 574 # Create the Quadlet file 575 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).kube 576 cat > $quadlet_file <<EOF 577 [Kube] 578 Yaml=${yaml_source} 579 EOF 580 581 run_quadlet "$quadlet_file" 582 service_setup $QUADLET_SERVICE_NAME 583 584 # Ensure we have output. 585 wait_for_output "STARTED CONTAINER" $pod_name-$container_name 586 587 run_podman container inspect --format "{{.State.Status}}" test_pod-test 588 is "$output" "running" "container should be started by systemd and hence be running" 589 590 service_cleanup $QUADLET_SERVICE_NAME inactive 591 run_podman rmi $(pause_image) 592 } 593 594 @test "quadlet kube - named network dependency" { 595 # Save the unit name to use as the network for the container 596 local quadlet_network_unit=dep_$(random_string).network 597 local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit} 598 cat > $quadlet_network_file <<EOF 599 [Network] 600 NetworkName=foo 601 EOF 602 603 # Have quadlet create the systemd unit file for the network unit 604 local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX) 605 run_quadlet "$quadlet_network_file" "$quadlet_tmpdir" 606 607 # Save the network service name since the variable will be overwritten 608 local network_service=$QUADLET_SERVICE_NAME 609 local network_name="foo" 610 611 # Create the YAMl file 612 pod_name="test_pod" 613 container_name="test" 614 yaml_source="$PODMAN_TMPDIR/basic_$(random_string).yaml" 615 cat >$yaml_source <<EOF 616 apiVersion: v1 617 kind: Pod 618 metadata: 619 labels: 620 app: test 621 name: $pod_name 622 spec: 623 containers: 624 - command: 625 - "sh" 626 args: 627 - "-c" 628 - "echo STARTED CONTAINER; top -b" 629 image: $IMAGE 630 name: $container_name 631 EOF 632 633 # Create the Quadlet file 634 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).kube 635 cat > $quadlet_file <<EOF 636 [Kube] 637 Yaml=${yaml_source} 638 Network=$quadlet_network_unit 639 EOF 640 641 # Network should not exist 642 run_podman 1 network exists $network_name 643 644 run_quadlet "$quadlet_file" "$quadlet_tmpdir" 645 service_setup $QUADLET_SERVICE_NAME 646 647 # Network system unit should be active 648 run systemctl show --property=ActiveState "$network_service" 649 assert "$output" = "ActiveState=active" "network should be active via dependency" 650 651 # Network should exist 652 run_podman network exists $network_name 653 654 # Ensure we have output. 655 wait_for_output "STARTED CONTAINER" $pod_name-$container_name 656 657 run_podman container inspect --format "{{.State.Status}}" test_pod-test 658 assert "$output" =~ "running" "container should be started by systemd and hence be running" 659 660 # Container should be attached to defined network 661 run_podman container inspect --format "{{index .NetworkSettings.Networks \"$network_name\"}}" test_pod-test 662 assert "$output" != "<nil>" "container should be attached to network $network_name" 663 664 service_cleanup $QUADLET_SERVICE_NAME inactive 665 run_podman network rm $network_name 666 run_podman rmi $(pause_image) 667 } 668 669 @test "quadlet - rootfs" { 670 skip_if_no_selinux 671 skip_if_rootless 672 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 673 cat > $quadlet_file <<EOF 674 [Container] 675 Rootfs=/:O 676 Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; top -b" 677 Notify=yes 678 EOF 679 680 run_quadlet "$quadlet_file" 681 service_setup $QUADLET_SERVICE_NAME 682 683 wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME 684 } 685 686 @test "quadlet - selinux disable" { 687 skip_if_no_selinux 688 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 689 cat > $quadlet_file <<EOF 690 [Container] 691 Image=$IMAGE 692 SecurityLabelDisable=true 693 Exec=sh -c "echo STARTED CONTAINER; top -b" 694 EOF 695 696 run_quadlet "$quadlet_file" 697 service_setup $QUADLET_SERVICE_NAME 698 699 # Ensure we have output. Output is synced via sd-notify (socat in Exec) 700 wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME 701 702 run_podman container inspect --format "{{.ProcessLabel}}" $QUADLET_CONTAINER_NAME 703 is "$output" "" "container should be started without specifying a Process Label" 704 705 service_cleanup $QUADLET_SERVICE_NAME failed 706 } 707 708 @test "quadlet - selinux labels" { 709 skip_if_no_selinux 710 NAME=$(random_string) 711 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 712 cat > $quadlet_file <<EOF 713 [Container] 714 ContainerName=$NAME 715 Image=$IMAGE 716 SecurityLabelType=spc_t 717 SecurityLabelLevel=s0:c100,c200 718 SecurityLabelFileType=container_ro_file_t 719 Exec=sh -c "echo STARTED CONTAINER; top -b" 720 EOF 721 722 run_quadlet "$quadlet_file" 723 service_setup $QUADLET_SERVICE_NAME 724 725 # Ensure we have output. Output is synced via sd-notify (socat in Exec) 726 wait_for_output "STARTED CONTAINER" $NAME 727 728 run_podman container ps 729 run_podman container inspect --format "{{.ProcessLabel}}" $NAME 730 is "$output" "system_u:system_r:spc_t:s0:c100,c200" "container should be started with correct Process Label" 731 run_podman container inspect --format "{{.MountLabel}}" $NAME 732 is "$output" "system_u:object_r:container_ro_file_t:s0:c100,c200" "container should be started with correct Mount Label" 733 734 service_cleanup $QUADLET_SERVICE_NAME failed 735 } 736 737 @test "quadlet - secret as environment variable" { 738 create_secret 739 740 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 741 cat > $quadlet_file <<EOF 742 [Container] 743 ContainerName=$NAME 744 Image=$IMAGE 745 Secret=$SECRET_NAME,type=env,target=MYSECRET 746 Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; top -b" 747 Notify=yes 748 EOF 749 750 run_quadlet "$quadlet_file" 751 service_setup $QUADLET_SERVICE_NAME 752 753 # Ensure we have output. Output is synced via sd-notify (socat in Exec) 754 wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME 755 756 run_podman exec $QUADLET_CONTAINER_NAME /bin/sh -c "printenv MYSECRET" 757 is "$output" $SECRET 758 759 service_cleanup $QUADLET_SERVICE_NAME failed 760 remove_secret $SECRET_NAME 761 } 762 763 @test "quadlet - secret as a file" { 764 create_secret 765 766 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 767 cat > $quadlet_file <<EOF 768 [Container] 769 ContainerName=$NAME 770 Image=$IMAGE 771 Secret=$SECRET_NAME,type=mount,target=/root/secret 772 Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; top -b" 773 Notify=yes 774 EOF 775 776 run_quadlet "$quadlet_file" 777 service_setup $QUADLET_SERVICE_NAME 778 779 # Ensure we have output. Output is synced via sd-notify (socat in Exec) 780 wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME 781 782 run_podman exec $QUADLET_CONTAINER_NAME /bin/sh -c "cat /root/secret" 783 is "$output" $SECRET 784 785 service_cleanup $QUADLET_SERVICE_NAME failed 786 remove_secret $SECRET_NAME 787 } 788 789 @test "quadlet - volume path using systemd %T specifier" { 790 # "specifier" is systemd-speak for "replaceable fields"; see systemd.unit(5) 791 # 792 # Step 1: determine what systemd is using for %T. There does not 793 # seem to be any systemctly way to find this. 794 percent_t_file="${PODMAN_TMPDIR}/foo" 795 local service=get-percent-t.$(random_string 10).service 796 local unitfile=${UNIT_DIR}/$service 797 cat >$unitfile <<EOF 798 [Unit] 799 Description=Get the value of percent T 800 801 [Service] 802 ExecStart=/bin/bash -c "echo %T >$percent_t_file" 803 Type=oneshot 804 EOF 805 systemctl daemon-reload 806 systemctl_start --wait $service 807 percent_t=$(< $percent_t_file) 808 # Clean up. Don't bother to systemctl-reload, service_setup does that below. 809 rm -f $unitfile 810 811 # Sanity check: just make sure it's not "/" 812 assert "${#percent_t}" -ge 4 "sanity check: length of %T ($percent_t)" 813 814 # Step 2: Make a subdirectory in %T, and in there, a scratch file 815 local tmp_path=$(mktemp -d --tmpdir=${percent_t} quadlet.volume.XXXXXX) 816 local tmp_subdir=$(basename $tmp_path) 817 local file_name="f$(random_string 10).txt" 818 local file_content="data_$(random_string 15)" 819 echo $file_content > $tmp_path/$file_name 820 821 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 822 cat > $quadlet_file <<EOF 823 [Container] 824 Image=$IMAGE 825 Volume=%T/$tmp_subdir:/test_content:Z 826 Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; top" 827 Notify=yes 828 EOF 829 830 run_quadlet "$quadlet_file" 831 service_setup $QUADLET_SERVICE_NAME 832 833 run_podman exec $QUADLET_CONTAINER_NAME cat /test_content/$file_name 834 is "$output" "$file_content" "contents of testfile in container volume" 835 836 rm -rf $tmp_path 837 } 838 839 @test "quadlet - tmpfs" { 840 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 841 cat > $quadlet_file <<EOF 842 [Container] 843 Image=$IMAGE 844 Exec=top 845 Tmpfs=/tmpfs1 846 Tmpfs=/tmpfs2:ro 847 EOF 848 849 run_quadlet "$quadlet_file" 850 service_setup $QUADLET_SERVICE_NAME 851 852 run_podman container inspect --format '{{index .HostConfig.Tmpfs "/tmpfs1"}}' $QUADLET_CONTAINER_NAME 853 is "$output" "rw,rprivate,nosuid,nodev,tmpcopyup" "regular tmpfs mount" 854 855 run_podman container inspect --format '{{index .HostConfig.Tmpfs "/tmpfs2"}}' $QUADLET_CONTAINER_NAME 856 is "$output" "ro,rprivate,nosuid,nodev,tmpcopyup" "read-only tmpfs mount" 857 858 run_podman container inspect --format '{{index .HostConfig.Tmpfs "/tmpfs3"}}' $QUADLET_CONTAINER_NAME 859 is "$output" "" "nonexistent tmpfs mount" 860 861 service_cleanup $QUADLET_SERVICE_NAME failed 862 } 863 864 @test "quadlet - userns" { 865 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container 866 cat > $quadlet_file <<EOF 867 [Container] 868 Image=$IMAGE 869 Exec=top 870 UserNS=keep-id:uid=200,gid=210 871 EOF 872 873 run_quadlet "$quadlet_file" 874 service_setup $QUADLET_SERVICE_NAME 875 876 run_podman container inspect --format '{{.Config.CreateCommand}}' $QUADLET_CONTAINER_NAME 877 is "${output/* --userns keep-id:uid=200,gid=210 */found}" "found" 878 879 service_cleanup $QUADLET_SERVICE_NAME failed 880 } 881 882 @test "quadlet - exit-code propagation" { 883 pod_name="test_pod" 884 container_name="ctr" 885 exit_tests=" 886 all | true | 0 | inactive 887 all | false | 137 | failed 888 none | false | 0 | inactive 889 " 890 while read exit_code_prop cmd exit_code service_state; do 891 local basename=propagate-${exit_code_prop}-${cmd}-$(random_string) 892 local quadlet_file=$PODMAN_TMPDIR/$basename.kube 893 local yaml_file=$PODMAN_TMPDIR/$basename.yaml 894 895 cat > $yaml_file <<EOF 896 apiVersion: v1 897 kind: Pod 898 metadata: 899 labels: 900 app: test 901 name: $pod_name 902 spec: 903 restartPolicy: Never 904 containers: 905 - name: $container_name 906 image: $IMAGE 907 command: 908 - $cmd 909 EOF 910 cat > $quadlet_file <<EOF 911 [Kube] 912 Yaml=$yaml_file 913 ExitCodePropagation=$exit_code_prop 914 LogDriver=journald 915 EOF 916 917 run_quadlet "$quadlet_file" 918 run systemctl status $QUADLET_SERVICE_NAME 919 920 yaml_sha=$(sha256sum $yaml_file) 921 service_container="${yaml_sha:0:12}-service" 922 923 service_setup $QUADLET_SERVICE_NAME 924 925 # Ensure we have output. Output is synced via sd-notify (socat in Exec) 926 run journalctl "--since=$STARTED_TIME" --unit="$QUADLET_SERVICE_NAME" 927 is "$output" '.*Started.*\.service.*' 928 929 # Opportunistic test: confirm that the Propagation field got set. 930 # This is racy, because the container is short-lived and quadlet 931 # cleans up on exit (via kube-down in ExecStopPost). So we use '?' 932 # and only check output if the inspect succeeds. 933 run_podman '?' container inspect --format '{{.KubeExitCodePropagation}}' $service_container 934 if [[ $status -eq 0 ]]; then 935 is "$output" "$exit_code_prop" \ 936 "$basename: service container has the expected policy set in its annotations" 937 else 938 assert "$output" =~ "no such container $service_container" \ 939 "$basename: unexpected error from podman container inspect" 940 fi 941 942 # Container must stop of its own accord before we call service_cleanup(), 943 # otherwise the 'systemctl stop' there may affect the unit's status. 944 # Again, use '?' to handle the abovementioned race condition. 945 run_podman '?' wait $service_container 946 if [[ $status -eq 0 ]]; then 947 assert "$output" = "$exit_code" \ 948 "$basename: service container reflects expected exit code" 949 else 950 assert "$output" =~ "no container with name or ID" \ 951 "$basename: unexpected error from podman wait" 952 fi 953 954 # This is the actual propagation check 955 service_cleanup $QUADLET_SERVICE_NAME $service_state 956 run_podman ps -aq 957 is "$output" "" "all containers are cleaned up even in case of errors" 958 done < <(parse_table "$exit_tests") 959 960 run_podman rmi $(pause_image) 961 } 962 963 @test "quadlet kube - Working Directory" { 964 yaml_source="$PODMAN_TMPDIR/basic_$(random_string).yaml" 965 local_path=local_path$(random_string) 966 pod_name=test_pod 967 container_name=test 968 969 cat >$yaml_source <<EOF 970 apiVersion: v1 971 kind: Pod 972 metadata: 973 labels: 974 app: test 975 name: $pod_name 976 spec: 977 containers: 978 - command: 979 - "sh" 980 args: 981 - "-c" 982 - "echo STARTED CONTAINER; top -b" 983 image: $IMAGE 984 name: $container_name 985 volumeMounts: 986 - mountPath: /test 987 name: test-volume 988 volumes: 989 - name: test-volume 990 hostPath: 991 # directory location on host 992 path: ./$local_path 993 # this field is optional 994 type: DirectoryOrCreate 995 EOF 996 997 # Create the Quadlet file 998 local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).kube 999 cat > $quadlet_file <<EOF 1000 [Kube] 1001 Yaml=${yaml_source} 1002 SetWorkingDirectory=yaml 1003 EOF 1004 1005 run_quadlet "$quadlet_file" 1006 service_setup $QUADLET_SERVICE_NAME 1007 1008 # Ensure we have output. 1009 wait_for_output "STARTED CONTAINER" $pod_name-$container_name 1010 1011 run_podman container inspect --format "{{.State.Status}}" $pod_name-$container_name 1012 is "$output" "running" "container should be started by systemd and hence be running" 1013 1014 run_podman ps 1015 1016 run_podman exec $pod_name-$container_name /bin/sh -c "echo hello > /test/test.txt" 1017 is $(cat $PODMAN_TMPDIR/$local_path/test.txt) "hello" 1018 1019 service_cleanup $QUADLET_SERVICE_NAME inactive 1020 run_podman rmi $(pause_image) 1021 } 1022 1023 @test "quadlet - image files" { 1024 local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets 1025 1026 local registry=localhost:${PODMAN_LOGIN_REGISTRY_PORT} 1027 local image_for_test=$registry/quadlet_image_test:$(random_string) 1028 local authfile=$PODMAN_TMPDIR/authfile.json 1029 1030 local quadlet_image_unit=image_test_$(random_string).image 1031 local quadlet_image_file=$PODMAN_TMPDIR/$quadlet_image_unit 1032 cat > $quadlet_image_file <<EOF 1033 [Image] 1034 Image=$image_for_test 1035 AuthFile=$authfile 1036 TLSVerify=false 1037 EOF 1038 1039 local quadlet_volume_unit=image_test_$(random_string).volume 1040 local quadlet_volume_file=$PODMAN_TMPDIR/$quadlet_volume_unit 1041 local volume_name=systemd-$(basename $quadlet_volume_file .volume) 1042 cat > $quadlet_volume_file <<EOF 1043 [Volume] 1044 Driver=image 1045 Image=$quadlet_image_unit 1046 EOF 1047 1048 local quadlet_container_unit=image_test_$(random_string).container 1049 local quadlet_container_file=$PODMAN_TMPDIR/$quadlet_container_unit 1050 cat > $quadlet_container_file <<EOF 1051 [Container] 1052 Image=$quadlet_image_unit 1053 Volume=$quadlet_volume_unit:/vol 1054 Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; sleep inf" 1055 EOF 1056 1057 # In order to test image pull but without possible Network issues, 1058 # this test uses an additional registry. 1059 # Start the registry and populate the authfile that we can use for the test. 1060 start_registry 1061 run_podman login --authfile=$authfile \ 1062 --tls-verify=false \ 1063 --username ${PODMAN_LOGIN_USER} \ 1064 --password ${PODMAN_LOGIN_PASS} \ 1065 $registry 1066 1067 # Push the test image to the registry 1068 run_podman image tag $IMAGE $image_for_test 1069 run_podman image push --tls-verify=false --authfile=$authfile $image_for_test 1070 1071 # Remove the local image to make sure it will be pulled again 1072 run_podman image rm --ignore $image_for_test 1073 1074 # Use the same directory for all quadlet files to make sure later steps access previous ones 1075 mkdir $quadlet_tmpdir 1076 1077 # Have quadlet create the systemd unit file for the image unit 1078 run_quadlet "$quadlet_image_file" "$quadlet_tmpdir" 1079 # Save the image service name since the variable will be overwritten 1080 local image_service=$QUADLET_SERVICE_NAME 1081 1082 # Have quadlet create the systemd unit file for the volume unit 1083 run_quadlet "$quadlet_volume_file" "$quadlet_tmpdir" 1084 # Save the image service name since the variable will be overwritten 1085 local volume_service=$QUADLET_SERVICE_NAME 1086 1087 # Image should not exist 1088 run_podman 1 image exists ${image_for_test} 1089 # Volume should not exist 1090 run_podman 1 volume exists ${volume_name} 1091 1092 # Have quadlet create the systemd unit file for the image unit 1093 run_quadlet "$quadlet_container_file" "$quadlet_tmpdir" 1094 local container_service=$QUADLET_SERVICE_NAME 1095 local container_name=$QUADLET_CONTAINER_NAME 1096 1097 service_setup $container_service 1098 1099 # Image system unit should be active 1100 run systemctl show --property=ActiveState "$image_service" 1101 assert "$output" = "ActiveState=active" \ 1102 "quadlet - image files: image should be active via dependency but is not" 1103 1104 # Volume system unit should be active 1105 run systemctl show --property=ActiveState "$volume_service" 1106 assert "$output" = "ActiveState=active" \ 1107 "quadlet - image files: volume should be active via dependency but is not" 1108 1109 # Image should exist 1110 run_podman image exists ${image_for_test} 1111 1112 # Volume should exist 1113 run_podman volume exists ${volume_name} 1114 1115 # Verify that the volume was created correctly 1116 run_podman volume inspect --format "{{ .Driver }}" $volume_name 1117 assert "$output" = "image" \ 1118 "quadlet - image files: volume driver should be image" 1119 1120 run_podman volume inspect --format "{{ .Options.image }}" $volume_name 1121 assert "$output" = "$image_for_test" \ 1122 "quadlet - image files: the image for the volume should be $image_for_test" 1123 1124 # Verify that the container mounts the volume 1125 run_podman container inspect --format "{{(index .Mounts 0).Type}}" $container_name 1126 assert "$output" = "volume" \ 1127 "quadlet - image files: container should be attached to a volume of type volume" 1128 1129 run_podman container inspect --format "{{(index .Mounts 0).Name}}" $container_name 1130 assert "$output" = "$volume_name" \ 1131 "quadlet - image files: container should be attached to the volume named $volume_name" 1132 1133 run_podman exec $QUADLET_CONTAINER_NAME cat /home/podman/testimage-id 1134 assert "$output" = $PODMAN_TEST_IMAGE_TAG \ 1135 "quadlet - image files: incorrect testimage-id in root" 1136 1137 run_podman exec $QUADLET_CONTAINER_NAME cat /vol/home/podman/testimage-id 1138 assert "$output" = $PODMAN_TEST_IMAGE_TAG \ 1139 "quadlet - image files: incorrect testimage-id in bound volume" 1140 1141 # Shutdown the service and remove the volume 1142 service_cleanup $container_service failed 1143 run_podman volume rm $volume_name 1144 run_podman image rm --ignore $image_for_test 1145 } 1146 1147 @test "quadlet - kube oneshot" { 1148 local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets 1149 local test_random_string=$(random_string) 1150 1151 local quadlet_kube_volume_name=test-volume_$test_random_string 1152 local quadlet_kube_volume_yaml_file=$PODMAN_TMPDIR/volume_$test_random_string.yaml 1153 cat > $quadlet_kube_volume_yaml_file <<EOF 1154 --- 1155 apiVersion: v1 1156 kind: PersistentVolumeClaim 1157 metadata: 1158 name: $quadlet_kube_volume_name 1159 spec: 1160 accessModes: 1161 - ReadWriteOnce 1162 resources: 1163 requests: 1164 storage: 1Gi 1165 EOF 1166 1167 local quadlet_kube_volume_unit_file=$PODMAN_TMPDIR/volume_$test_random_string.kube 1168 cat > $quadlet_kube_volume_unit_file <<EOF 1169 [Kube] 1170 Yaml=$quadlet_kube_volume_yaml_file 1171 1172 [Service] 1173 Type=oneshot 1174 RemainAfterExit=yes 1175 EOF 1176 1177 local pod_name="test_pod_$test_random_string" 1178 local container_name="test" 1179 local quadlet_kube_pod_yaml_file=$PODMAN_TMPDIR/pod_$test_random_string.yaml 1180 cat > $quadlet_kube_pod_yaml_file <<EOF 1181 apiVersion: v1 1182 kind: Pod 1183 metadata: 1184 labels: 1185 app: test 1186 name: $pod_name 1187 spec: 1188 containers: 1189 - command: 1190 - "sh" 1191 args: 1192 - "-c" 1193 - "echo STARTED CONTAINER; top -b" 1194 image: $IMAGE 1195 name: $container_name 1196 volumeMounts: 1197 - name: storage 1198 mountPath: /mnt/storage 1199 volumes: 1200 - name: storage 1201 persistentVolumeClaim: 1202 claimName: $quadlet_kube_volume_name 1203 EOF 1204 1205 # Use the same directory for all quadlet files to make sure later steps access previous ones 1206 mkdir $quadlet_tmpdir 1207 1208 # Have quadlet create the systemd unit file for the kube based volume unit 1209 run_quadlet "$quadlet_kube_volume_unit_file" "$quadlet_tmpdir" 1210 # Save the volume service name since the variable will be overwritten 1211 local volume_service=$QUADLET_SERVICE_NAME 1212 1213 # Volume should not exist 1214 run_podman 1 volume exists ${quadlet_kube_volume_name} 1215 1216 local quadlet_kube_pod_unit_file=$PODMAN_TMPDIR/pod_$test_random_string.kube 1217 cat > $quadlet_kube_pod_unit_file <<EOF 1218 [Kube] 1219 Yaml=$quadlet_kube_pod_yaml_file 1220 1221 [Unit] 1222 Requires=$volume_service 1223 After=$volume_service 1224 EOF 1225 1226 # Have quadlet create the systemd unit file for the pod unit 1227 run_quadlet "$quadlet_kube_pod_unit_file" "$quadlet_tmpdir" 1228 local pod_service=$QUADLET_SERVICE_NAME 1229 1230 service_setup $pod_service 1231 1232 # Volume system unit should be active 1233 run systemctl show --property=ActiveState "$volume_service" 1234 assert "$output" = "ActiveState=active" \ 1235 "quadlet - kube oneshot: volume should be active via dependency but is not" 1236 1237 # Volume should exist 1238 run_podman volume exists ${quadlet_kube_volume_name} 1239 1240 run_podman container inspect --format "{{(index .Mounts 0).Type}}" $pod_name-$container_name 1241 assert "$output" = "volume" \ 1242 "quadlet - kube oneshot: volume .Type" 1243 1244 run_podman container inspect --format "{{(index .Mounts 0).Name}}" $pod_name-$container_name 1245 assert "$output" = "$quadlet_kube_volume_name" \ 1246 "quadlet - kube oneshot: volume .Name" 1247 1248 # Shutdown the service and remove the volume 1249 service_cleanup $pod_service inactive 1250 run_podman volume rm $quadlet_kube_volume_name 1251 run_podman rmi --ignore $(pause_image) 1252 } 1253 1254 @test "quadlet - kube down force" { 1255 local test_random_string=$(random_string) 1256 1257 local quadlet_kube_volume_name=test-volume_$test_random_string 1258 local pod_name="test_pod_$test_random_string" 1259 local container_name="test" 1260 local quadlet_kube_pod_yaml_file=$PODMAN_TMPDIR/pod_$test_random_string.yaml 1261 cat > $quadlet_kube_pod_yaml_file <<EOF 1262 --- 1263 apiVersion: v1 1264 kind: PersistentVolumeClaim 1265 metadata: 1266 name: $quadlet_kube_volume_name 1267 spec: 1268 accessModes: 1269 - ReadWriteOnce 1270 resources: 1271 requests: 1272 storage: 1Gi 1273 --- 1274 apiVersion: v1 1275 kind: Pod 1276 metadata: 1277 labels: 1278 app: test 1279 name: $pod_name 1280 spec: 1281 containers: 1282 - command: 1283 - "sh" 1284 args: 1285 - "-c" 1286 - "echo STARTED CONTAINER; top -b" 1287 image: $IMAGE 1288 name: $container_name 1289 volumeMounts: 1290 - name: storage 1291 mountPath: /mnt/storage 1292 volumes: 1293 - name: storage 1294 persistentVolumeClaim: 1295 claimName: $quadlet_kube_volume_name 1296 EOF 1297 1298 local quadlet_kube_pod_unit_file=$PODMAN_TMPDIR/pod_$test_random_string.kube 1299 cat > $quadlet_kube_pod_unit_file <<EOF 1300 [Kube] 1301 Yaml=$quadlet_kube_pod_yaml_file 1302 KubeDownForce=true 1303 EOF 1304 1305 # Have quadlet create the systemd unit file for the pod unit 1306 run_quadlet "$quadlet_kube_pod_unit_file" "$quadlet_tmpdir" 1307 local pod_service=$QUADLET_SERVICE_NAME 1308 1309 # Volume should not exist 1310 run_podman 1 volume exists ${quadlet_kube_volume_name} 1311 1312 service_setup $pod_service 1313 1314 # Volume should exist 1315 run_podman volume exists ${quadlet_kube_volume_name} 1316 1317 run_podman container inspect --format "{{(index .Mounts 0).Type}}" $pod_name-$container_name 1318 assert "$output" = "volume" \ 1319 "quadlet - kube oneshot: volume .Type" 1320 1321 run_podman container inspect --format "{{(index .Mounts 0).Name}}" $pod_name-$container_name 1322 assert "$output" = "$quadlet_kube_volume_name" \ 1323 "quadlet - kube oneshot: volume .Name" 1324 1325 # Shutdown the service 1326 service_cleanup $pod_service failed 1327 1328 # Volume should not exist 1329 run_podman 1 volume exists ${quadlet_kube_volume_name} 1330 run_podman rmi --ignore $(pause_image) 1331 } 1332 1333 @test "quadlet - image tag" { 1334 local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets 1335 local archive_file=$PODMAN_TMPDIR/archive-file.tar 1336 local image_for_test=localhost/quadlet_image_test:$(random_string) 1337 1338 local quadlet_image_unit=image_test_$(random_string).image 1339 local quadlet_image_file=$PODMAN_TMPDIR/$quadlet_image_unit 1340 cat > $quadlet_image_file <<EOF 1341 [Image] 1342 Image=docker-archive:$archive_file 1343 ImageTag=$image_for_test 1344 EOF 1345 1346 local quadlet_volume_unit=image_test_$(random_string).volume 1347 local quadlet_volume_file=$PODMAN_TMPDIR/$quadlet_volume_unit 1348 local volume_name=systemd-$(basename $quadlet_volume_file .volume) 1349 cat > $quadlet_volume_file <<EOF 1350 [Volume] 1351 Driver=image 1352 Image=$quadlet_image_unit 1353 EOF 1354 1355 local quadlet_container_unit=image_test_$(random_string).container 1356 local quadlet_container_file=$PODMAN_TMPDIR/$quadlet_container_unit 1357 cat > $quadlet_container_file <<EOF 1358 [Container] 1359 Image=$IMAGE 1360 Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; sleep inf" 1361 Volume=$quadlet_volume_unit:/vol 1362 EOF 1363 1364 # Tag the image, save it into a file and remove it 1365 run_podman image tag $IMAGE $image_for_test 1366 run_podman image save --format docker-archive --output $archive_file $image_for_test 1367 run_podman image rm $image_for_test 1368 1369 # Use the same directory for all quadlet files to make sure later steps access previous ones 1370 mkdir $quadlet_tmpdir 1371 1372 # Have quadlet create the systemd unit file for the image unit 1373 run_quadlet "$quadlet_image_file" "$quadlet_tmpdir" 1374 # Save the image service name since the variable will be overwritten 1375 local image_service=$QUADLET_SERVICE_NAME 1376 1377 # Have quadlet create the systemd unit file for the volume unit 1378 run_quadlet "$quadlet_volume_file" "$quadlet_tmpdir" 1379 # Save the image service name since the variable will be overwritten 1380 local volume_service=$QUADLET_SERVICE_NAME 1381 1382 # Image should not exist 1383 run_podman 1 image exists ${image_for_test} 1384 # Volume should not exist 1385 run_podman 1 volume exists ${volume_name} 1386 1387 # Have quadlet create the systemd unit file for the image unit 1388 run_quadlet "$quadlet_container_file" "$quadlet_tmpdir" 1389 local container_service=$QUADLET_SERVICE_NAME 1390 local container_name=$QUADLET_CONTAINER_NAME 1391 1392 service_setup $container_service 1393 1394 # Image system unit should be active 1395 run systemctl show --property=ActiveState "$image_service" 1396 assert "$output" = "ActiveState=active" \ 1397 "quadlet - image tag: image service ActiveState" 1398 1399 # Volume system unit should be active 1400 run systemctl show --property=ActiveState "$volume_service" 1401 assert "$output" = "ActiveState=active" \ 1402 "quadlet - image tag: volume service ActiveState" 1403 1404 # Image should exist 1405 run_podman image exists ${image_for_test} 1406 1407 # Volume should exist 1408 run_podman volume exists ${volume_name} 1409 1410 run_podman exec $QUADLET_CONTAINER_NAME cat /vol/home/podman/testimage-id 1411 assert "$output" = $PODMAN_TEST_IMAGE_TAG \ 1412 "quadlet - image files: incorrect testimage-id in bound volume" 1413 1414 # Shutdown the service and remove the image 1415 service_cleanup $container_service failed 1416 run_podman image rm --ignore $image_for_test 1417 run_podman rmi --ignore $(pause_image) 1418 } 1419 1420 @test "quadlet - pod simple" { 1421 local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets 1422 1423 local test_pod_name=pod_test_$(random_string) 1424 local quadlet_pod_unit=$test_pod_name.pod 1425 local quadlet_pod_file=$PODMAN_TMPDIR/$quadlet_pod_unit 1426 cat > $quadlet_pod_file <<EOF 1427 [Pod] 1428 PodName=$test_pod_name 1429 EOF 1430 1431 local quadlet_container_unit=pod_test_$(random_string).container 1432 local quadlet_container_file=$PODMAN_TMPDIR/$quadlet_container_unit 1433 cat > $quadlet_container_file <<EOF 1434 [Container] 1435 Image=$IMAGE 1436 Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; sleep inf" 1437 Pod=$quadlet_pod_unit 1438 EOF 1439 1440 # Use the same directory for all quadlet files to make sure later steps access previous ones 1441 mkdir $quadlet_tmpdir 1442 1443 # Have quadlet create the systemd unit file for the pod unit 1444 run_quadlet "$quadlet_pod_file" "$quadlet_tmpdir" 1445 # Save the pod service name since the variable will be overwritten 1446 local pod_service=$QUADLET_SERVICE_NAME 1447 1448 # Have quadlet create the systemd unit file for the container unit 1449 run_quadlet "$quadlet_container_file" "$quadlet_tmpdir" 1450 local container_service=$QUADLET_SERVICE_NAME 1451 local container_name=$QUADLET_CONTAINER_NAME 1452 1453 # Start the pod service 1454 service_setup $pod_service 1455 1456 # Pod should exist 1457 run_podman pod exists ${test_pod_name} 1458 1459 # Wait for systemd to activate the container service 1460 wait_for_command_output "systemctl show --property=ActiveState $container_service" "ActiveState=active" 1461 1462 # Container should exist 1463 run_podman container exists ${container_name} 1464 1465 # Shutdown the service 1466 service_cleanup $pod_service inactive 1467 1468 # The service of the container should be active 1469 run systemctl show --property=ActiveState "$container_service" 1470 assert "ActiveState=failed" \ 1471 "quadlet - pod base: container service ActiveState" 1472 1473 # Container should not exist 1474 run_podman 1 container exists ${container_name} 1475 1476 run_podman rmi $(pause_image) 1477 } 1478 1479 # This test reproduces https://github.com/containers/podman/issues/20432 1480 # In order to reproduce the issue, the image in the FROM must no be available locally 1481 # and must not have a tag. The first forces Pull and the second the resolution where the crash occurs 1482 # Using a local registry does not work since kube play does not pass the autofile and tls-verify flags to the build 1483 @test "quadlet - kube build from unavailable image with no tag" { 1484 local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets 1485 1486 local untagged_image=quay.io/libpod/busybox 1487 local built_image=test_image 1488 local yaml_dir=$quadlet_tmpdir/$built_image 1489 local build_dir=$yaml_dir/$built_image 1490 1491 # Use the same directory for all quadlet files to make sure later steps access previous ones 1492 mkdir -p $build_dir 1493 1494 container_file_path=$build_dir/Containerfile 1495 cat >$container_file_path << EOF 1496 FROM $untagged_image 1497 EOF 1498 1499 # Create the YAMl file 1500 pod_name="test_pod" 1501 container_name="test" 1502 yaml_source="$yaml_dir/build_$(random_string).yaml" 1503 cat >$yaml_source <<EOF 1504 apiVersion: v1 1505 kind: Pod 1506 metadata: 1507 labels: 1508 app: test 1509 name: $pod_name 1510 spec: 1511 containers: 1512 - command: 1513 - "sh" 1514 args: 1515 - "-c" 1516 - "echo STARTED CONTAINER; sleep inf" 1517 image: $built_image 1518 name: $container_name 1519 EOF 1520 1521 # Create the Quadlet file 1522 local quadlet_file=$quadlet_tmpdir/build_$(random_string).kube 1523 cat > $quadlet_file <<EOF 1524 [Kube] 1525 Yaml=${yaml_source} 1526 PodmanArgs=--build 1527 SetWorkingDirectory=yaml 1528 EOF 1529 1530 # Make sure the tagged image is not locally available 1531 run_podman rmi -i $untagged_image:latest 1532 1533 run_quadlet "$quadlet_file" 1534 service_setup $QUADLET_SERVICE_NAME 1535 1536 # Ensure we have output. 1537 wait_for_output "STARTED CONTAINER" $pod_name-$container_name 1538 1539 run_podman container inspect --format "{{.State.Status}}" test_pod-test 1540 is "$output" "running" "container should be started by systemd and hence be running" 1541 1542 service_cleanup $QUADLET_SERVICE_NAME inactive 1543 run_podman rmi $untagged_image:latest $built_image $(pause_image) 1544 } 1545 # vim: filetype=sh