From d446ae89c0168f17eed7135ac06df3b294b3fcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= Date: Fri, 3 Apr 2020 09:13:51 +0200 Subject: [PATCH] test: add test for cgroup v2 freezer support --- test/TEST-38-FREEZER/Makefile | 1 + test/TEST-38-FREEZER/test.sh | 7 + test/test-functions | 1 + test/units/testsuite-38-sleep.service | 2 + test/units/testsuite-38.service | 6 + test/units/testsuite-38.sh | 293 ++++++++++++++++++++++++++ 6 files changed, 310 insertions(+) create mode 120000 test/TEST-38-FREEZER/Makefile create mode 100755 test/TEST-38-FREEZER/test.sh create mode 100644 test/units/testsuite-38-sleep.service create mode 100644 test/units/testsuite-38.service create mode 100755 test/units/testsuite-38.sh diff --git a/test/TEST-38-FREEZER/Makefile b/test/TEST-38-FREEZER/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-38-FREEZER/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-38-FREEZER/test.sh b/test/TEST-38-FREEZER/test.sh new file mode 100755 index 0000000000..3821db9f00 --- /dev/null +++ b/test/TEST-38-FREEZER/test.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e +TEST_DESCRIPTION="test unit freezing and thawing via DBus and systemctl" +TEST_NO_NSPAWN=1 +. $TEST_BASE_DIR/test-functions + +do_test "$@" 38 diff --git a/test/test-functions b/test/test-functions index 8389623c20..90b6705238 100644 --- a/test/test-functions +++ b/test/test-functions @@ -101,6 +101,7 @@ BASICTOOLS=( tar tee test + timeout touch tr true diff --git a/test/units/testsuite-38-sleep.service b/test/units/testsuite-38-sleep.service new file mode 100644 index 0000000000..859f97b360 --- /dev/null +++ b/test/units/testsuite-38-sleep.service @@ -0,0 +1,2 @@ +[Service] +ExecStart=/bin/sleep 3600 diff --git a/test/units/testsuite-38.service b/test/units/testsuite-38.service new file mode 100644 index 0000000000..c848840ba0 --- /dev/null +++ b/test/units/testsuite-38.service @@ -0,0 +1,6 @@ +[Unit] +Description=TEST-38-FREEZER + +[Service] +ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh +Type=oneshot diff --git a/test/units/testsuite-38.sh b/test/units/testsuite-38.sh new file mode 100755 index 0000000000..6fcadb8f8e --- /dev/null +++ b/test/units/testsuite-38.sh @@ -0,0 +1,293 @@ +#!/usr/bin/env bash + +set -ex +set -o pipefail + +systemd-analyze log-level debug +systemd-analyze log-target console + +unit=testsuite-38-sleep.service + +start_test_service() { + systemctl daemon-reload + systemctl start "${unit}" +} + +dbus_freeze() { + local suffix= + suffix="${1##*.}" + + local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)" + local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}" + + busctl call \ + org.freedesktop.systemd1 \ + "${object_path}" \ + org.freedesktop.systemd1.Unit \ + Freeze +} + +dbus_thaw() { + local suffix= + suffix="${1##*.}" + + local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)" + local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}" + + busctl call \ + org.freedesktop.systemd1 \ + "${object_path}" \ + org.freedesktop.systemd1.Unit \ + Thaw +} + +dbus_freeze_unit() { + busctl call \ + org.freedesktop.systemd1 \ + /org/freedesktop/systemd1 \ + org.freedesktop.systemd1.Manager \ + FreezeUnit \ + s \ + "$1" +} + +dbus_thaw_unit() { + busctl call \ + org.freedesktop.systemd1 \ + /org/freedesktop/systemd1 \ + org.freedesktop.systemd1.Manager \ + ThawUnit \ + s \ + "$1" +} + +dbus_can_freeze() { + local suffix= + suffix="${1##*.}" + + local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)" + local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}" + + busctl get-property \ + org.freedesktop.systemd1 \ + "${object_path}" \ + org.freedesktop.systemd1.Unit \ + CanFreeze +} + +check_freezer_state() { + local suffix= + suffix="${1##*.}" + + local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)" + local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}" + + state=$(busctl get-property \ + org.freedesktop.systemd1 \ + "${object_path}" \ + org.freedesktop.systemd1.Unit \ + FreezerState | cut -d " " -f2 | tr -d '"') + + [ "$state" = "$2" ] || { + echo "error: unexpected freezer state, expected: $2, actual: $state" >&2 + exit 1 + } +} + +check_cgroup_state() { + grep -q "frozen $2" /sys/fs/cgroup/system.slice/"$1"/cgroup.events +} + +test_dbus_api() { + echo "Test that DBus API works:" + echo -n " - Freeze(): " + dbus_freeze "${unit}" + check_freezer_state "${unit}" "frozen" + check_cgroup_state "$unit" 1 + echo "[ OK ]" + + echo -n " - Thaw(): " + dbus_thaw "${unit}" + check_freezer_state "${unit}" "running" + check_cgroup_state "$unit" 0 + echo "[ OK ]" + + echo -n " - FreezeUnit(): " + dbus_freeze_unit "${unit}" + check_freezer_state "${unit}" "frozen" + check_cgroup_state "$unit" 1 + echo "[ OK ]" + + echo -n " - ThawUnit(): " + dbus_thaw_unit "${unit}" + check_freezer_state "${unit}" "running" + check_cgroup_state "$unit" 0 + echo "[ OK ]" + + echo -n " - CanFreeze(): " + output=$(dbus_can_freeze "${unit}") + [ "$output" = "b true" ] + echo "[ OK ]" + + echo +} + +test_jobs() { + local pid_before= + local pid_after= + echo "Test that it is possible to apply jobs on frozen units:" + + systemctl start "${unit}" + dbus_freeze "${unit}" + check_freezer_state "${unit}" "frozen" + + echo -n " - restart: " + pid_before=$(systemctl show -p MainPID "${unit}" --value) + systemctl restart "${unit}" + pid_after=$(systemctl show -p MainPID "${unit}" --value) + [ "$pid_before" != "$pid_after" ] && echo "[ OK ]" + + dbus_freeze "${unit}" + check_freezer_state "${unit}" "frozen" + + echo -n " - stop: " + timeout 5s systemctl stop "${unit}" + echo "[ OK ]" + + echo +} + +test_systemctl() { + echo "Test that systemctl freeze/thaw verbs:" + + systemctl start "$unit" + + echo -n " - freeze: " + systemctl freeze "$unit" + check_freezer_state "${unit}" "frozen" + check_cgroup_state "$unit" 1 + # Freezing already frozen unit should be NOP and return quickly + timeout 3s systemctl freeze "$unit" + echo "[ OK ]" + + echo -n " - thaw: " + systemctl thaw "$unit" + check_freezer_state "${unit}" "running" + check_cgroup_state "$unit" 0 + # Likewise thawing already running unit shouldn't block + timeout 3s systemctl thaw "$unit" + echo "[ OK ]" + + systemctl stop "$unit" + + echo +} + +test_systemctl_show() { + echo "Test systemctl show integration:" + + systemctl start "$unit" + + echo -n " - FreezerState property: " + state=$(systemctl show -p FreezerState --value "$unit") + [ "$state" = "running" ] + systemctl freeze "$unit" + state=$(systemctl show -p FreezerState --value "$unit") + [ "$state" = "frozen" ] + systemctl thaw "$unit" + echo "[ OK ]" + + echo -n " - CanFreeze property: " + state=$(systemctl show -p CanFreeze --value "$unit") + [ "$state" = "yes" ] + echo "[ OK ]" + + systemctl stop "$unit" + echo +} + +test_recursive() { + local slice="bar.slice" + local unit="baz.service" + + systemd-run --unit "$unit" --slice "$slice" sleep 3600 >/dev/null 2>&1 + + echo "Test recursive freezing:" + + echo -n " - freeze: " + systemctl freeze "$slice" + check_freezer_state "${slice}" "frozen" + check_freezer_state "${unit}" "frozen" + grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/cgroup.events + grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events + echo "[ OK ]" + + echo -n " - thaw: " + systemctl thaw "$slice" + check_freezer_state "${unit}" "running" + check_freezer_state "${slice}" "running" + grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events + grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events + echo "[ OK ]" + + systemctl stop "$unit" + systemctl stop "$slice" + + echo +} + +test_preserve_state() { + local slice="bar.slice" + local unit="baz.service" + + systemd-run --unit "$unit" --slice "$slice" sleep 3600 >/dev/null 2>&1 + + echo "Test that freezer state is preserved when recursive freezing is initiated from outside (e.g. by manager up the tree):" + + echo -n " - freeze from outside: " + echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze + + # Our state should not be affected + check_freezer_state "${slice}" "running" + check_freezer_state "${unit}" "running" + + # However actual kernel state should be frozen + grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/cgroup.events + grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events + echo "[ OK ]" + + echo -n " - thaw from outside: " + echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze + check_freezer_state "${unit}" "running" + check_freezer_state "${slice}" "running" + grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events + grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events + echo "[ OK ]" + + echo -n " - thaw from outside while inner service is frozen: " + systemctl freeze "$unit" + check_freezer_state "${unit}" "frozen" + echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze + echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze + check_freezer_state "${slice}" "running" + check_freezer_state "${unit}" "frozen" + echo "[ OK ]" + + systemctl stop "$unit" + systemctl stop "$slice" + + echo +} + +test -e /sys/fs/cgroup/system.slice/cgroup.freeze && { + start_test_service + test_dbus_api + test_systemctl + test_systemctl_show + test_jobs + test_recursive + test_preserve_state +} + +echo OK > /testok +exit 0