Skip to content

Commit

Permalink
feature to honor first shutdown request to completion
Browse files Browse the repository at this point in the history
Create unit tests per established norm

check in_set first before getting unit
  • Loading branch information
ejb42 committed Jun 15, 2020
1 parent 562ffac commit e89406d
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 11 deletions.
35 changes: 24 additions & 11 deletions src/core/emergency-action.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@
#include "terminal-util.h"
#include "virt.h"

static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
[EMERGENCY_ACTION_NONE] = "none",
[EMERGENCY_ACTION_REBOOT] = "reboot",
[EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
[EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
[EMERGENCY_ACTION_POWEROFF] = "poweroff",
[EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
[EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
[EMERGENCY_ACTION_EXIT] = "exit",
[EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
};

static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) {
log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason);
if (warn)
Expand All @@ -28,10 +40,22 @@ void emergency_action(
int exit_status,
const char *reason) {

Unit *u;

assert(m);
assert(action >= 0);
assert(action < _EMERGENCY_ACTION_MAX);

/* Is the special shutdown target active or queued? If so, we are in shutdown state */
if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) {
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
if (u && unit_active_or_pending(u)) {
log_notice("Shutdown is already active. Skipping emergency action request %s.",
emergency_action_table[action]);
return;
}
}

if (action == EMERGENCY_ACTION_NONE)
return;

Expand Down Expand Up @@ -126,17 +150,6 @@ void emergency_action(
}
}

static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
[EMERGENCY_ACTION_NONE] = "none",
[EMERGENCY_ACTION_REBOOT] = "reboot",
[EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
[EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
[EMERGENCY_ACTION_POWEROFF] = "poweroff",
[EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
[EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
[EMERGENCY_ACTION_EXIT] = "exit",
[EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
};
DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);

int parse_emergency_action(
Expand Down
16 changes: 16 additions & 0 deletions test/TEST-48-HONORFIRSTSHUTDOWN/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
BUILD_DIR=$(shell ../../tools/find-build-dir.sh)

all setup run clean clean-again:
@basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@

# finish option is used to run checks that can only be run outside of
# the test execution. Example case, honor first shutdown, proof is obtained
# from the console output as the image shuts down. This does not show up in
# the journal so the output from the do_test is captured in a file in /tmp.
# Without the use of finish the test will still pass because if it fails
# the test will loop and will be terminated via a command timeout.
# This just provides concrete confirmation.
finish:
@basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./fini.sh --$@

.PHONY: all setup run clean clean-again
10 changes: 10 additions & 0 deletions test/TEST-48-HONORFIRSTSHUTDOWN/fini.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
TEST_DESCRIPTION="test honor first shutdown"

if grep -q "Shutdown is already active. Skipping emergency action request" /tmp/honorfirstshutdown.log; then
echo "$TEST_DESCRIPTION [pass]"
exit 0
else
echo "$TEST_DESCRIPTION [fail]"
exit 1
fi
19 changes: 19 additions & 0 deletions test/TEST-48-HONORFIRSTSHUTDOWN/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash
set -e
. $TEST_BASE_DIR/test-functions
TEST_REQUIRE_INSTALL_TESTS=0
TEST_DESCRIPTION="testing honor first shutdown"
#INTERACTIVE_DEBUG=1
TEST_NO_QEMU=1

#Using timeout because if the test fails it can loop.
# The reason is because the poweroff executed by end.service
# could turn into a reboot if the test fails.
NSPAWN_TIMEOUT=20

#Remove this file if it exists. this is used along with
# the make target "finish". Since concrete confirmaion is
# only found from the console during the poweroff.
rm -f /tmp/honorfirstshutdown.log >/dev/null

do_test "$@" 48 > /tmp/honorfirstshutdown.log
2 changes: 2 additions & 0 deletions test/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ install_subdir('testsuite-28.units',
install_dir : testdata_dir)
install_subdir('testsuite-30.units',
install_dir : testdata_dir)
install_subdir('testsuite-48.units',
install_dir : testdata_dir)

testsuite08_dir = testdata_dir + '/testsuite-08.units'
install_data('testsuite-08.units/-.mount',
Expand Down
6 changes: 6 additions & 0 deletions test/testsuite-48.units/testsuite-48.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[Unit]
Description=Testsuite service

[Service]
ExecStart=/usr/lib/systemd/tests/testdata/%N.units/%N.sh
Type=oneshot
18 changes: 18 additions & 0 deletions test/testsuite-48.units/testsuite-48.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
set -ex
set -o pipefail

if ! test -x /usr/lib/systemd/tests/testdata/units/test-honor-first-shutdown.sh ; then
echo "honor-first-shutdown script not found - FAIL" > /testok
exit 0
fi

systemd-analyze log-level debug
systemd-analyze log-target console

systemctl enable test-honor-first-shutdown.service
systemctl start test-honor-first-shutdown.service

echo OK > /testok

exit 0
11 changes: 11 additions & 0 deletions test/units/test-honor-first-shutdown.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=Honor First Shutdown feature
After=multi-user.target

[Service]
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
ExecStop=sh -c 'kill -SIGKILL $MAINPID'
FailureAction=reboot

[Install]
WantedBy=multi-user.target
3 changes: 3 additions & 0 deletions test/units/test-honor-first-shutdown.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
echo "Honor first shutdown test script"
sleep infinity;

0 comments on commit e89406d

Please sign in to comment.