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