github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/tests/integration/update.bats (about) 1 #!/usr/bin/env bats 2 3 load helpers 4 5 function teardown() { 6 rm -f "$BATS_RUN_TMPDIR"/runc-cgroups-integration-test.json 7 teardown_bundle 8 } 9 10 function setup() { 11 setup_busybox 12 13 set_cgroups_path 14 15 # Set some initial known values 16 update_config ' .linux.resources.memory |= {"limit": 33554432, "reservation": 25165824} 17 | .linux.resources.cpu |= {"shares": 100, "quota": 500000, "period": 1000000} 18 | .linux.resources.pids |= {"limit": 20}' 19 } 20 21 # Tests whatever limits are (more or less) common between cgroup 22 # v1 and v2: memory/swap, pids, and cpuset. 23 @test "update cgroup v1/v2 common limits" { 24 [ $EUID -ne 0 ] && requires rootless_cgroup 25 requires cgroups_memory cgroups_pids cgroups_cpuset 26 init_cgroup_paths 27 28 # run a few busyboxes detached 29 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 30 [ "$status" -eq 0 ] 31 32 # Set a few variables to make the code below work for both v1 and v2 33 if [ -v CGROUP_V1 ]; then 34 MEM_LIMIT="memory.limit_in_bytes" 35 SD_MEM_LIMIT="MemoryLimit" 36 MEM_RESERVE="memory.soft_limit_in_bytes" 37 SD_MEM_RESERVE="unsupported" 38 MEM_SWAP="memory.memsw.limit_in_bytes" 39 SD_MEM_SWAP="unsupported" 40 SYSTEM_MEM=$(cat "${CGROUP_MEMORY_BASE_PATH}/${MEM_LIMIT}") 41 HAVE_SWAP="no" 42 if [ -f "${CGROUP_MEMORY_BASE_PATH}/${MEM_SWAP}" ]; then 43 HAVE_SWAP="yes" 44 fi 45 else 46 MEM_LIMIT="memory.max" 47 SD_MEM_LIMIT="MemoryMax" 48 MEM_RESERVE="memory.low" 49 SD_MEM_RESERVE="MemoryLow" 50 MEM_SWAP="memory.swap.max" 51 SD_MEM_SWAP="MemorySwapMax" 52 SYSTEM_MEM="max" 53 HAVE_SWAP="yes" 54 fi 55 56 SD_UNLIMITED="infinity" 57 SD_VERSION=$(systemctl --version | awk '{print $2; exit}') 58 if [ "$SD_VERSION" -lt 227 ]; then 59 SD_UNLIMITED="18446744073709551615" 60 fi 61 62 # check that initial values were properly set 63 check_cgroup_value $MEM_LIMIT 33554432 64 check_systemd_value $SD_MEM_LIMIT 33554432 65 66 check_cgroup_value $MEM_RESERVE 25165824 67 check_systemd_value $SD_MEM_RESERVE 25165824 68 69 check_cgroup_value "pids.max" 20 70 check_systemd_value "TasksMax" 20 71 72 # update cpuset if possible (i.e. we're running on a multicore cpu) 73 cpu_count=$(grep -c '^processor' /proc/cpuinfo) 74 if [ "$cpu_count" -gt 1 ]; then 75 runc update test_update --cpuset-cpus "1" 76 [ "$status" -eq 0 ] 77 check_cgroup_value "cpuset.cpus" 1 78 fi 79 80 # update memory limit 81 runc update test_update --memory 67108864 82 [ "$status" -eq 0 ] 83 check_cgroup_value $MEM_LIMIT 67108864 84 check_systemd_value $SD_MEM_LIMIT 67108864 85 86 runc update test_update --memory 50M 87 [ "$status" -eq 0 ] 88 check_cgroup_value $MEM_LIMIT 52428800 89 check_systemd_value $SD_MEM_LIMIT 52428800 90 91 # update memory soft limit 92 runc update test_update --memory-reservation 33554432 93 [ "$status" -eq 0 ] 94 check_cgroup_value "$MEM_RESERVE" 33554432 95 check_systemd_value "$SD_MEM_RESERVE" 33554432 96 97 # Run swap memory tests if swap is available 98 if [ "$HAVE_SWAP" = "yes" ]; then 99 # try to remove memory swap limit 100 runc update test_update --memory-swap -1 101 [ "$status" -eq 0 ] 102 check_cgroup_value "$MEM_SWAP" "$SYSTEM_MEM" 103 check_systemd_value "$SD_MEM_SWAP" "$SD_UNLIMITED" 104 105 # update memory swap 106 if [ -v CGROUP_V2 ]; then 107 # for cgroupv2, memory and swap can only be set together 108 runc update test_update --memory 52428800 --memory-swap 96468992 109 [ "$status" -eq 0 ] 110 # for cgroupv2, swap is a separate limit (it does not include mem) 111 check_cgroup_value "$MEM_SWAP" $((96468992 - 52428800)) 112 check_systemd_value "$SD_MEM_SWAP" $((96468992 - 52428800)) 113 else 114 runc update test_update --memory-swap 96468992 115 [ "$status" -eq 0 ] 116 check_cgroup_value "$MEM_SWAP" 96468992 117 check_systemd_value "$SD_MEM_SWAP" 96468992 118 fi 119 fi 120 121 # try to remove memory limit 122 runc update test_update --memory -1 123 [ "$status" -eq 0 ] 124 125 # check memory limit is gone 126 check_cgroup_value "$MEM_LIMIT" "$SYSTEM_MEM" 127 check_systemd_value "$SD_MEM_LIMIT" "$SD_UNLIMITED" 128 129 # check swap memory limited is gone 130 if [ "$HAVE_SWAP" = "yes" ]; then 131 check_cgroup_value "$MEM_SWAP" "$SYSTEM_MEM" 132 check_systemd_value "$SD_MEM_SWAP" "$SD_UNLIMITED" 133 fi 134 135 # update pids limit 136 runc update test_update --pids-limit 10 137 [ "$status" -eq 0 ] 138 check_cgroup_value "pids.max" 10 139 check_systemd_value "TasksMax" 10 140 141 # unlimited 142 runc update test_update --pids-limit -1 143 [ "$status" -eq 0 ] 144 check_cgroup_value "pids.max" max 145 check_systemd_value "TasksMax" $SD_UNLIMITED 146 147 # Revert to the test initial value via json on stdin 148 runc update -r - test_update <<EOF 149 { 150 "memory": { 151 "limit": 33554432, 152 "reservation": 25165824 153 }, 154 "cpu": { 155 "shares": 100, 156 "quota": 500000, 157 "period": 1000000, 158 "cpus": "0" 159 }, 160 "pids": { 161 "limit": 20 162 } 163 } 164 EOF 165 [ "$status" -eq 0 ] 166 check_cgroup_value "cpuset.cpus" 0 167 168 check_cgroup_value $MEM_LIMIT 33554432 169 check_systemd_value $SD_MEM_LIMIT 33554432 170 171 check_cgroup_value $MEM_RESERVE 25165824 172 check_systemd_value $SD_MEM_RESERVE 25165824 173 174 check_cgroup_value "pids.max" 20 175 check_systemd_value "TasksMax" 20 176 177 # redo all the changes at once 178 runc update test_update \ 179 --cpu-period 900000 --cpu-quota 600000 --cpu-share 200 \ 180 --memory 67108864 --memory-reservation 33554432 \ 181 --pids-limit 10 182 [ "$status" -eq 0 ] 183 check_cgroup_value $MEM_LIMIT 67108864 184 check_systemd_value $SD_MEM_LIMIT 67108864 185 186 check_cgroup_value $MEM_RESERVE 33554432 187 check_systemd_value $SD_MEM_RESERVE 33554432 188 189 check_cgroup_value "pids.max" 10 190 check_systemd_value "TasksMax" 10 191 192 # reset to initial test value via json file 193 cat <<EOF >"$BATS_RUN_TMPDIR"/runc-cgroups-integration-test.json 194 { 195 "memory": { 196 "limit": 33554432, 197 "reservation": 25165824 198 }, 199 "cpu": { 200 "shares": 100, 201 "quota": 500000, 202 "period": 1000000, 203 "cpus": "0" 204 }, 205 "pids": { 206 "limit": 20 207 } 208 } 209 EOF 210 211 runc update -r "$BATS_RUN_TMPDIR"/runc-cgroups-integration-test.json test_update 212 [ "$status" -eq 0 ] 213 check_cgroup_value "cpuset.cpus" 0 214 215 check_cgroup_value $MEM_LIMIT 33554432 216 check_systemd_value $SD_MEM_LIMIT 33554432 217 218 check_cgroup_value $MEM_RESERVE 25165824 219 check_systemd_value $SD_MEM_RESERVE 25165824 220 221 check_cgroup_value "pids.max" 20 222 check_systemd_value "TasksMax" 20 223 224 if [ "$HAVE_SWAP" = "yes" ]; then 225 # Test case for https://github.com/opencontainers/runc/pull/592, 226 # checking libcontainer/cgroups/fs/memory.go:setMemoryAndSwap. 227 228 runc update test_update --memory 30M --memory-swap 50M 229 [ "$status" -eq 0 ] 230 231 check_cgroup_value $MEM_LIMIT $((30 * 1024 * 1024)) 232 check_systemd_value $SD_MEM_LIMIT $((30 * 1024 * 1024)) 233 234 if [ -v CGROUP_V2 ]; then 235 # for cgroupv2, swap does not include mem 236 check_cgroup_value "$MEM_SWAP" $((20 * 1024 * 1024)) 237 check_systemd_value "$SD_MEM_SWAP" $((20 * 1024 * 1024)) 238 else 239 check_cgroup_value "$MEM_SWAP" $((50 * 1024 * 1024)) 240 check_systemd_value "$SD_MEM_SWAP" $((50 * 1024 * 1024)) 241 fi 242 243 # Now, set new memory to more than old swap 244 runc update test_update --memory 60M --memory-swap 80M 245 [ "$status" -eq 0 ] 246 247 check_cgroup_value $MEM_LIMIT $((60 * 1024 * 1024)) 248 check_systemd_value $SD_MEM_LIMIT $((60 * 1024 * 1024)) 249 250 if [ -v CGROUP_V2 ]; then 251 # for cgroupv2, swap does not include mem 252 check_cgroup_value "$MEM_SWAP" $((20 * 1024 * 1024)) 253 check_systemd_value "$SD_MEM_SWAP" $((20 * 1024 * 1024)) 254 else 255 check_cgroup_value "$MEM_SWAP" $((80 * 1024 * 1024)) 256 check_systemd_value "$SD_MEM_SWAP" $((80 * 1024 * 1024)) 257 fi 258 fi 259 } 260 261 @test "update cgroup cpu limits" { 262 [ $EUID -ne 0 ] && requires rootless_cgroup 263 264 # run a few busyboxes detached 265 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 266 [ "$status" -eq 0 ] 267 268 # check that initial values were properly set 269 check_cpu_quota 500000 1000000 "500ms" 270 check_cpu_shares 100 271 272 # update cpu period 273 runc update test_update --cpu-period 900000 274 [ "$status" -eq 0 ] 275 check_cpu_quota 500000 900000 "560ms" 276 277 # update cpu quota 278 runc update test_update --cpu-quota 600000 279 [ "$status" -eq 0 ] 280 check_cpu_quota 600000 900000 "670ms" 281 282 # remove cpu quota 283 runc update test_update --cpu-quota -1 284 [ "$status" -eq 0 ] 285 check_cpu_quota -1 900000 "infinity" 286 287 # update cpu-shares 288 runc update test_update --cpu-share 200 289 [ "$status" -eq 0 ] 290 check_cpu_shares 200 291 292 # Revert to the test initial value via json on stding 293 runc update -r - test_update <<EOF 294 { 295 "cpu": { 296 "shares": 100, 297 "quota": 500000, 298 "period": 1000000 299 } 300 } 301 EOF 302 [ "$status" -eq 0 ] 303 check_cpu_quota 500000 1000000 "500ms" 304 305 # redo all the changes at once 306 runc update test_update \ 307 --cpu-period 900000 --cpu-quota 600000 --cpu-share 200 308 [ "$status" -eq 0 ] 309 check_cpu_quota 600000 900000 "670ms" 310 check_cpu_shares 200 311 312 # remove cpu quota and reset the period 313 runc update test_update --cpu-quota -1 --cpu-period 100000 314 [ "$status" -eq 0 ] 315 check_cpu_quota -1 100000 "infinity" 316 317 # reset to initial test value via json file 318 cat <<EOF >"$BATS_RUN_TMPDIR"/runc-cgroups-integration-test.json 319 { 320 "cpu": { 321 "shares": 100, 322 "quota": 500000, 323 "period": 1000000 324 } 325 } 326 EOF 327 [ "$status" -eq 0 ] 328 329 runc update -r "$BATS_RUN_TMPDIR"/runc-cgroups-integration-test.json test_update 330 [ "$status" -eq 0 ] 331 check_cpu_quota 500000 1000000 "500ms" 332 check_cpu_shares 100 333 } 334 335 @test "cpu burst" { 336 [ $EUID -ne 0 ] && requires rootless_cgroup 337 requires cgroups_cpu_burst 338 339 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 340 [ "$status" -eq 0 ] 341 check_cpu_burst 0 342 343 runc update test_update --cpu-period 900000 --cpu-burst 500000 344 [ "$status" -eq 0 ] 345 check_cpu_burst 500000 346 347 # issue: https://github.com/opencontainers/runc/issues/4210 348 # for systemd, cpu-burst value will be cleared, it's a known issue. 349 if [ ! -v RUNC_USE_SYSTEMD ]; then 350 runc update test_update --memory 100M 351 [ "$status" -eq 0 ] 352 check_cpu_burst 500000 353 fi 354 355 runc update test_update --cpu-period 900000 --cpu-burst 0 356 [ "$status" -eq 0 ] 357 check_cpu_burst 0 358 } 359 360 @test "set cpu period with no quota" { 361 [ $EUID -ne 0 ] && requires rootless_cgroup 362 363 update_config '.linux.resources.cpu |= { "period": 1000000 }' 364 365 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 366 [ "$status" -eq 0 ] 367 368 check_cpu_quota -1 1000000 "infinity" 369 } 370 371 @test "set cpu period with no quota (invalid period)" { 372 [ $EUID -ne 0 ] && requires rootless_cgroup 373 374 update_config '.linux.resources.cpu |= { "period": 100 }' 375 376 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 377 [ "$status" -eq 1 ] 378 } 379 380 @test "set cpu quota with no period" { 381 [ $EUID -ne 0 ] && requires rootless_cgroup 382 383 update_config '.linux.resources.cpu |= { "quota": 5000 }' 384 385 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 386 [ "$status" -eq 0 ] 387 check_cpu_quota 5000 100000 "50ms" 388 } 389 390 @test "update cpu period with no previous period/quota set" { 391 [ $EUID -ne 0 ] && requires rootless_cgroup 392 393 update_config '.linux.resources.cpu |= {}' 394 395 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 396 [ "$status" -eq 0 ] 397 398 # update the period alone, no old values were set 399 runc update --cpu-period 50000 test_update 400 [ "$status" -eq 0 ] 401 check_cpu_quota -1 50000 "infinity" 402 } 403 404 @test "update cpu quota with no previous period/quota set" { 405 [ $EUID -ne 0 ] && requires rootless_cgroup 406 407 update_config '.linux.resources.cpu |= {}' 408 409 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 410 [ "$status" -eq 0 ] 411 412 # update the quota alone, no old values were set 413 runc update --cpu-quota 30000 test_update 414 [ "$status" -eq 0 ] 415 check_cpu_quota 30000 100000 "300ms" 416 } 417 418 @test "update cpu period in a pod cgroup with pod limit set" { 419 requires cgroups_v1 420 [ $EUID -ne 0 ] && requires rootless_cgroup 421 422 set_cgroups_path "pod_${RANDOM}" 423 424 # Set parent/pod CPU quota limit to 50%. 425 if [ -v RUNC_USE_SYSTEMD ]; then 426 set_parent_systemd_properties CPUQuota="50%" 427 else 428 echo 50000 >"/sys/fs/cgroup/cpu/$REL_PARENT_PATH/cpu.cfs_quota_us" 429 fi 430 # Sanity checks. 431 run cat "/sys/fs/cgroup/cpu$REL_PARENT_PATH/cpu.cfs_period_us" 432 [ "$output" -eq 100000 ] 433 run cat "/sys/fs/cgroup/cpu$REL_PARENT_PATH/cpu.cfs_quota_us" 434 [ "$output" -eq 50000 ] 435 436 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 437 [ "$status" -eq 0 ] 438 # Get the current period. 439 local cur 440 cur=$(get_cgroup_value cpu.cfs_period_us) 441 442 # Sanity check: as the parent cgroup sets the limit to 50%, 443 # setting a higher limit (e.g. 60%) is expected to fail. 444 runc update --cpu-quota $((cur * 6 / 10)) test_update 445 [ "$status" -eq 1 ] 446 447 # Finally, the test itself: set 30% limit but with lower period. 448 runc update --cpu-period 10000 --cpu-quota 3000 test_update 449 [ "$status" -eq 0 ] 450 check_cpu_quota 3000 10000 "300ms" 451 } 452 453 @test "update cgroup cpu.idle" { 454 requires cgroups_cpu_idle 455 [ $EUID -ne 0 ] && requires rootless_cgroup 456 457 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 458 [ "$status" -eq 0 ] 459 460 check_cgroup_value "cpu.idle" "0" 461 462 local val 463 for val in 1 0 1; do 464 runc update -r - test_update <<EOF 465 { 466 "cpu": { 467 "idle": $val 468 } 469 } 470 EOF 471 [ "$status" -eq 0 ] 472 check_cgroup_value "cpu.idle" "$val" 473 done 474 475 for val in 1 0 1; do 476 runc update --cpu-idle "$val" test_update 477 478 [ "$status" -eq 0 ] 479 check_cgroup_value "cpu.idle" "$val" 480 done 481 482 # Values other than 1 or 0 are ignored by the kernel, see 483 # sched_group_set_idle() in kernel/sched/fair.c. 484 # 485 # If this ever fails, it means that the kernel now accepts values 486 # other than 0 or 1, and runc needs to adopt. 487 for val in -1 2 3; do 488 runc update --cpu-idle "$val" test_update 489 [ "$status" -ne 0 ] 490 check_cgroup_value "cpu.idle" "1" 491 done 492 493 # https://github.com/opencontainers/runc/issues/3786 494 [ "$(systemd_version)" -ge 252 ] && return 495 # test update other option won't impact on cpu.idle 496 runc update --cpu-period 10000 test_update 497 [ "$status" -eq 0 ] 498 check_cgroup_value "cpu.idle" "1" 499 } 500 501 @test "update cgroup cpu.idle via systemd v252+" { 502 requires cgroups_v2 systemd_v252 cgroups_cpu_idle 503 [ $EUID -ne 0 ] && requires rootless_cgroup 504 505 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 506 [ "$status" -eq 0 ] 507 check_cgroup_value "cpu.idle" "0" 508 509 # If cpu-idle is set, cpu-share (converted to CPUWeight) can't be set via systemd. 510 runc update --cpu-share 200 --cpu-idle 1 test_update 511 [[ "$output" == *"unable to apply both"* ]] 512 check_cgroup_value "cpu.idle" "1" 513 514 # Changing cpu-shares (converted to CPU weight) resets cpu.idle to 0. 515 runc update --cpu-share 200 test_update 516 check_cgroup_value "cpu.idle" "0" 517 518 # Setting values via unified map. 519 520 # If cpu.idle is set, cpu.weight is ignored. 521 runc update -r - test_update <<EOF 522 { 523 "unified": { 524 "cpu.idle": "1", 525 "cpu.weight": "8" 526 } 527 } 528 EOF 529 [[ "$output" == *"unable to apply both"* ]] 530 check_cgroup_value "cpu.idle" "1" 531 532 # Setting any cpu.weight should reset cpu.idle to 0. 533 runc update -r - test_update <<EOF 534 { 535 "unified": { 536 "cpu.weight": "8" 537 } 538 } 539 EOF 540 check_cgroup_value "cpu.idle" "0" 541 } 542 543 @test "update cgroup v2 resources via unified map" { 544 [ $EUID -ne 0 ] && requires rootless_cgroup 545 requires cgroups_v2 546 547 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 548 [ "$status" -eq 0 ] 549 550 # check that initial values were properly set 551 check_cpu_quota 500000 1000000 "500ms" 552 # initial cpu shares of 100 corresponds to weight of 4 553 check_cpu_weight 4 554 check_systemd_value "TasksMax" 20 555 556 runc update -r - test_update <<EOF 557 { 558 "unified": { 559 "cpu.max": "max 100000", 560 "cpu.weight": "16", 561 "pids.max": "10" 562 } 563 } 564 EOF 565 566 # check the updated systemd unit properties 567 check_cpu_quota -1 100000 "infinity" 568 check_cpu_weight 16 569 check_systemd_value "TasksMax" 10 570 } 571 572 @test "update cpuset parameters via resources.CPU" { 573 [ $EUID -ne 0 ] && requires rootless_cgroup 574 requires smp cgroups_cpuset 575 576 local AllowedCPUs='AllowedCPUs' AllowedMemoryNodes='AllowedMemoryNodes' 577 # these properties require systemd >= v244 578 if [ "$(systemd_version)" -lt 244 ]; then 579 # a hack to skip checks, see check_systemd_value() 580 AllowedCPUs='unsupported' 581 AllowedMemoryNodes='unsupported' 582 fi 583 584 update_config ' .linux.resources.CPU |= { 585 "Cpus": "0", 586 "Mems": "0" 587 }' 588 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 589 [ "$status" -eq 0 ] 590 591 # check that initial values were properly set 592 check_systemd_value "$AllowedCPUs" 0 593 check_systemd_value "$AllowedMemoryNodes" 0 594 595 runc update -r - test_update <<EOF 596 { 597 "CPU": { 598 "Cpus": "1" 599 } 600 } 601 EOF 602 [ "$status" -eq 0 ] 603 604 # check the updated systemd unit properties 605 check_systemd_value "$AllowedCPUs" 1 606 607 # More than 1 numa memory node is required to test this 608 file="/sys/fs/cgroup/cpuset.mems.effective" 609 if ! test -r $file || grep -q '^0$' $file; then 610 # skip the rest of it 611 return 0 612 fi 613 614 runc update -r - test_update <<EOF 615 { 616 "CPU": { 617 "Mems": "1" 618 } 619 } 620 EOF 621 [ "$status" -eq 0 ] 622 623 # check the updated systemd unit properties 624 check_systemd_value "$AllowedMemoryNodes" 1 625 } 626 627 @test "update cpuset parameters via v2 unified map" { 628 # This test assumes systemd >= v244 629 [ $EUID -ne 0 ] && requires rootless_cgroup 630 requires cgroups_v2 smp cgroups_cpuset 631 632 update_config ' .linux.resources.unified |= { 633 "cpuset.cpus": "0", 634 "cpuset.mems": "0" 635 }' 636 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 637 [ "$status" -eq 0 ] 638 639 # check that initial values were properly set 640 check_systemd_value "AllowedCPUs" 0 641 check_systemd_value "AllowedMemoryNodes" 0 642 643 runc update -r - test_update <<EOF 644 { 645 "unified": { 646 "cpuset.cpus": "1" 647 } 648 } 649 EOF 650 [ "$status" -eq 0 ] 651 652 # check the updated systemd unit properties 653 check_systemd_value "AllowedCPUs" 1 654 655 # More than 1 numa memory node is required to test this 656 file="/sys/fs/cgroup/cpuset.mems.effective" 657 if ! test -r $file || grep -q '^0$' $file; then 658 # skip the rest of it 659 return 0 660 fi 661 662 runc update -r - test_update <<EOF 663 { 664 "unified": { 665 "cpuset.mems": "1" 666 } 667 } 668 EOF 669 [ "$status" -eq 0 ] 670 671 # check the updated systemd unit properties 672 check_systemd_value "AllowedMemoryNodes" 1 673 } 674 675 @test "update cpuset cpus range via v2 unified map" { 676 # This test assumes systemd >= v244 677 [ $EUID -ne 0 ] && requires rootless_cgroup 678 requires systemd cgroups_v2 more_than_8_core cgroups_cpuset 679 680 update_config ' .linux.resources.unified |= { 681 "cpuset.cpus": "0-5", 682 }' 683 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 684 [ "$status" -eq 0 ] 685 686 # check that the initial value was properly set 687 check_systemd_value "AllowedCPUs" "0-5" 688 689 runc update -r - test_update <<EOF 690 { 691 "unified": { 692 "cpuset.cpus": "5-8" 693 } 694 } 695 EOF 696 [ "$status" -eq 0 ] 697 698 # check the updated systemd unit property, the value should not be affected by byte order 699 check_systemd_value "AllowedCPUs" "5-8" 700 } 701 702 @test "update rt period and runtime" { 703 [ $EUID -ne 0 ] && requires rootless_cgroup 704 requires cgroups_v1 cgroups_rt no_systemd 705 706 local cgroup_cpu="${CGROUP_CPU_BASE_PATH}/${REL_CGROUPS_PATH}" 707 708 # By default, "${cgroup_cpu}/cpu.rt_runtime_us" is set to 0, which inhibits 709 # setting the container's realtimeRuntime. (#2046) 710 # 711 # When ${cgroup_cpu} is "/sys/fs/cgroup/cpu,cpuacct/runc-cgroups-integration-test/test-cgroup", 712 # we write the values of /sys/fs/cgroup/cpu,cpuacct/cpu.rt_{period,runtime}_us to: 713 # - sys/fs/cgroup/cpu,cpuacct/runc-cgroups-integration-test/cpu.rt_{period,runtime}_us 714 # - sys/fs/cgroup/cpu,cpuacct/runc-cgroups-integration-test/test-cgroup/cpu.rt_{period,runtime}_us 715 # 716 # Typically period=1000000 runtime=950000 . 717 # 718 # TODO: support systemd 719 mkdir -p "$cgroup_cpu" 720 local root_period root_runtime 721 root_period=$(cat "${CGROUP_CPU_BASE_PATH}/cpu.rt_period_us") 722 root_runtime=$(cat "${CGROUP_CPU_BASE_PATH}/cpu.rt_runtime_us") 723 # the following IFS magic sets dirs=("runc-cgroups-integration-test" "test-cgroup") 724 IFS='/' read -r -a dirs <<<"${REL_CGROUPS_PATH#/}" 725 for ((i = 0; i < ${#dirs[@]}; i++)); do 726 local target="$CGROUP_CPU_BASE_PATH" 727 for ((j = 0; j <= i; j++)); do 728 target="${target}/${dirs[$j]}" 729 done 730 target_period="${target}/cpu.rt_period_us" 731 echo "Writing ${root_period} to ${target_period}" 732 echo "$root_period" >"$target_period" 733 target_runtime="${target}/cpu.rt_runtime_us" 734 echo "Writing ${root_runtime} to ${target_runtime}" 735 echo "$root_runtime" >"$target_runtime" 736 done 737 738 # run a detached busybox 739 runc run -d --console-socket "$CONSOLE_SOCKET" test_update_rt 740 [ "$status" -eq 0 ] 741 742 runc update -r - test_update_rt <<EOF 743 { 744 "cpu": { 745 "realtimeRuntime": 500001 746 } 747 } 748 EOF 749 [ "$status" -eq 0 ] 750 check_cgroup_value "cpu.rt_period_us" "$root_period" 751 check_cgroup_value "cpu.rt_runtime_us" 500001 752 753 runc update -r - test_update_rt <<EOF 754 { 755 "cpu": { 756 "realtimePeriod": 800001, 757 "realtimeRuntime": 500001 758 } 759 } 760 EOF 761 check_cgroup_value "cpu.rt_period_us" 800001 762 check_cgroup_value "cpu.rt_runtime_us" 500001 763 764 runc update test_update_rt --cpu-rt-period 900001 --cpu-rt-runtime 600001 765 [ "$status" -eq 0 ] 766 767 check_cgroup_value "cpu.rt_period_us" 900001 768 check_cgroup_value "cpu.rt_runtime_us" 600001 769 } 770 771 @test "update devices [minimal transition rules]" { 772 requires root 773 774 # Run a basic shell script that tries to read from /dev/kmsg, but 775 # due to lack of permissions, it prints the error message to /dev/null. 776 # If any data is read from /dev/kmsg, it will be printed to stdout, and the 777 # test will fail. In the same way, if access to /dev/null is denied, the 778 # error will be printed to stderr, and the test will also fail. 779 # 780 # "runc update" makes use of minimal transition rules, updates should not cause 781 # writes to fail at any point. For systemd cgroup driver on cgroup v1, the cgroup 782 # is frozen to ensure this. 783 update_config ' .linux.resources.devices = [{"allow": false, "access": "rwm"}, {"allow": false, "type": "c", "major": 1, "minor": 11, "access": "rwa"}] 784 | .linux.devices = [{"path": "/dev/kmsg", "type": "c", "major": 1, "minor": 11}] 785 | .process.capabilities.bounding += ["CAP_SYSLOG"] 786 | .process.capabilities.effective += ["CAP_SYSLOG"] 787 | .process.capabilities.permitted += ["CAP_SYSLOG"] 788 | .process.args |= ["sh", "-c", "while true; do head -c 100 /dev/kmsg 2> /dev/null; done"]' 789 790 # Set up a temporary console socket and recvtty so we can get the stdio. 791 TMP_RECVTTY_DIR="$(mktemp -d "$BATS_RUN_TMPDIR/runc-tmp-recvtty.XXXXXX")" 792 TMP_RECVTTY_PID="$TMP_RECVTTY_DIR/recvtty.pid" 793 TMP_CONSOLE_SOCKET="$TMP_RECVTTY_DIR/console.sock" 794 CONTAINER_OUTPUT="$TMP_RECVTTY_DIR/output" 795 ("$RECVTTY" --no-stdin --pid-file "$TMP_RECVTTY_PID" \ 796 --mode single "$TMP_CONSOLE_SOCKET" &>"$CONTAINER_OUTPUT") & 797 retry 10 0.1 [ -e "$TMP_CONSOLE_SOCKET" ] 798 799 # Run the container in the background. 800 runc run -d --console-socket "$TMP_CONSOLE_SOCKET" test_update 801 cat "$CONTAINER_OUTPUT" 802 [ "$status" -eq 0 ] 803 804 # Trigger an update. This update doesn't actually change the device rules, 805 # but it will trigger the devices cgroup code to reapply the current rules. 806 # We trigger the update a few times to make sure we hit the race. 807 for _ in {1..30}; do 808 # TODO: Update "runc update" so we can change the device rules. 809 runc update --pids-limit 30 test_update 810 [ "$status" -eq 0 ] 811 done 812 813 # Kill recvtty. 814 kill -9 "$(<"$TMP_RECVTTY_PID")" 815 816 # There should've been no output from the container. 817 cat "$CONTAINER_OUTPUT" 818 [ -z "$(<"$CONTAINER_OUTPUT")" ] 819 } 820 821 @test "update paused container" { 822 requires cgroups_freezer 823 [ $EUID -ne 0 ] && requires rootless_cgroup 824 825 # Run the container in the background. 826 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 827 [ "$status" -eq 0 ] 828 829 # Pause the container. 830 runc pause test_update 831 [ "$status" -eq 0 ] 832 833 # Trigger an unrelated update. 834 runc update --pids-limit 30 test_update 835 [ "$status" -eq 0 ] 836 837 # The container should still be paused. 838 testcontainer test_update paused 839 840 # Resume the container. 841 runc resume test_update 842 [ "$status" -eq 0 ] 843 } 844 845 @test "update memory vs CheckBeforeUpdate" { 846 requires cgroups_v2 847 [ $EUID -ne 0 ] && requires rootless_cgroup 848 849 runc run -d --console-socket "$CONSOLE_SOCKET" test_update 850 [ "$status" -eq 0 ] 851 852 # Setting memory to low value with checkBeforeUpdate=true should fail. 853 runc update -r - test_update <<EOF 854 { 855 "memory": { 856 "limit": 1024, 857 "checkBeforeUpdate": true 858 } 859 } 860 EOF 861 [ "$status" -ne 0 ] 862 [[ "$output" == *"rejecting memory limit"* ]] 863 testcontainer test_update running 864 865 # Setting memory+swap to low value with checkBeforeUpdate=true should fail. 866 runc update -r - test_update <<EOF 867 { 868 "memory": { 869 "limit": 1024, 870 "swap": 2048, 871 "checkBeforeUpdate": true 872 } 873 } 874 EOF 875 [ "$status" -ne 0 ] 876 [[ "$output" == *"rejecting memory+swap limit"* ]] 877 testcontainer test_update running 878 879 # The container will be OOM killed, and runc might either succeed 880 # or fail depending on the timing, so we don't check its exit code. 881 runc update test_update --memory 1024 882 wait_for_container 10 1 test_update stopped 883 }