-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merging dev into main. #4
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
._UG#_STORE | ||
.code-workspace | ||
._UG#_Store | ||
*.code-workspace |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -14,7 +14,9 @@ | |||||
readonly REBOOT_HINT_MARKER="${REBOOT_HINT_PATH}"/reboot-hint-marker | ||||||
readonly CONF_PATH=${CONF_PATH:-/etc/smart-restart-conf.d} | ||||||
readonly DENYLISTS=("${CONF_PATH}"/*-denylist) | ||||||
# shellcheck disable=SC2207 | ||||||
readonly PRE_RESTART=($(ls "$CONF_PATH"/*pre-restart | sort -n)) | ||||||
# shellcheck disable=SC2207 | ||||||
readonly POST_RESTART=($(ls "$CONF_PATH"/*post-restart | sort -n)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
|
||||||
SYSCTL_COMMAND="${SYSCTL_COMMAND:-systemctl}" | ||||||
|
@@ -25,14 +27,26 @@ | |||||
|
||||||
SERVICES=() | ||||||
BLOCKED_SERVICES=() | ||||||
PRE_RESTART_HEALTHY=0 | ||||||
POST_RESTART_HEALTHY=0 | ||||||
|
||||||
INF() { echo "$1"; } | ||||||
DBG() { [[ "$DEBUG" != "" ]] && >&2 echo "$1"; } | ||||||
CRIT() { >&2 echo "*** ERROR: $1"; } | ||||||
|
||||||
assert_root() { | ||||||
if [[ "$(id -u)" != "0" ]]; then | ||||||
CRIT "Please run this script as root." | ||||||
exit 1 | ||||||
fi | ||||||
return 0 | ||||||
} | ||||||
|
||||||
assemble_service_list() { | ||||||
# shellcheck disable=SC2207 | ||||||
local all_services=($($NEEDS_RESTARTING_COMMAND -s | xargs)) | ||||||
|
||||||
# shellcheck disable=SC2048 | ||||||
BLOCKED_SERVICES=("$(sed "s/#.*//g" ${DENYLISTS[*]})") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [shellcheck (suggestion)] reported by reviewdog 🐶
Suggested change
|
||||||
|
||||||
DBG "Denylist: ${DENYLISTS[*]}" | ||||||
|
@@ -41,7 +55,7 @@ | |||||
|
||||||
for SERVICE in "${all_services[@]}"; do | ||||||
grep -qF "${SERVICE}" <<<"${BLOCKED_SERVICES[*]}" | ||||||
if [[ $? -eq 0 ]]; then | ||||||
Check warning on line 58 in bin/smart-restart.sh GitHub Actions / shellcheck
|
||||||
DBG "Ignoring ${SERVICE}" | ||||||
else | ||||||
SERVICES+=("${SERVICE}") | ||||||
|
@@ -60,14 +74,16 @@ | |||||
restart_services() { | ||||||
local -i retval=0 | ||||||
|
||||||
if [[ ${#SERVICES[@]} != 0 ]]; then | ||||||
# shellcheck disable=SC2086 | ||||||
if [[ ${#SERVICES[@]} != 0 ]]; then | ||||||
DBG "Attempting to restart services: ${SERVICES[*]}" | ||||||
# shellcheck disable=SC2048 | ||||||
# shellcheck disable=SC2048,SC2086 | ||||||
$SYSCTL_COMMAND restart ${SERVICES[*]} || retval=$? | ||||||
else | ||||||
DBG "No services to restart" | ||||||
fi | ||||||
|
||||||
|
||||||
|
||||||
if [[ ! "${BLOCKED_SERVICES[*]}" =~ "systemd" ]]; then | ||||||
DBG "Attempting to restart systemd itself" | ||||||
$SYSCTL_COMMAND daemon-reexec || retval=$? | ||||||
|
@@ -77,6 +93,42 @@ | |||||
return $retval | ||||||
} | ||||||
|
||||||
# Though, {pre,post} health checks could live in restart_services(), I've moved them outside to be able to test the functionality. | ||||||
count_pre_restart_health() { | ||||||
DBG "No of services to check (pre-restart): ${#SERVICES[@]}" | ||||||
if [[ ${#SERVICES[@]} != 0 ]]; then | ||||||
# shellcheck disable=SC2048,SC2086 | ||||||
PRE_RESTART_HEALTHY=$($SYSCTL_COMMAND status ${SERVICES[*]} | grep "Active" | grep -cE "active \(running\)") | ||||||
fi | ||||||
} | ||||||
|
||||||
count_post_restart_health() { | ||||||
DBG "No of services to check (post-restart): ${#SERVICES[@]}" | ||||||
|
||||||
if [[ ${#SERVICES[@]} != 0 ]]; then | ||||||
# shellcheck disable=SC2048,SC2086 | ||||||
POST_RESTART_HEALTHY=$($SYSCTL_COMMAND status ${SERVICES[*]} | grep "Active" | grep -cE "active \(running\)") | ||||||
fi | ||||||
DBG "Pre restart cnt: $PRE_RESTART_HEALTHY" | ||||||
DBG "Post restart cnt: $POST_RESTART_HEALTHY" | ||||||
|
||||||
if [[ "$PRE_RESTART_HEALTHY" != "$POST_RESTART_HEALTHY" ]]; then | ||||||
S=() | ||||||
for SERVICE in "${SERVICES[@]}"; do | ||||||
$SYSCTL_COMMAND is-active ${SERVICE} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [shellcheck (suggestion)] reported by reviewdog 🐶
Suggested change
|
||||||
local -i retval=$? | ||||||
|
||||||
if [[ $retval -gt 0 ]]; then | ||||||
S+=("${SERVICE}") | ||||||
fi | ||||||
done | ||||||
|
||||||
CRIT "Not all services could be successfully started. Failed services: ${S[*]}" | ||||||
|
||||||
return 1 | ||||||
fi | ||||||
} | ||||||
|
||||||
execute_post_hooks() { | ||||||
DBG "Executing post-restart hooks: ${POST_RESTART[*]}" | ||||||
for HOOK in "${POST_RESTART[@]}"; do | ||||||
|
@@ -90,12 +142,14 @@ | |||||
# This means, we need to consolidate a few information sources here to be sure. | ||||||
# 1) Check if processess actually got restarted (and ignore the "denylisted" services) | ||||||
# 2) Remove userspace components from the reboot-hint output | ||||||
readonly OS_VERSION=$(cut -d ":" -f6 /etc/system-release-cpe) | ||||||
# shellcheck disable=SC2155 | ||||||
LOCAL_OS_VERSION=$(cut -d ":" -f6 /etc/system-release-cpe) | ||||||
OS_VERSION=${OS_VERSION:-$LOCAL_OS_VERSION} | ||||||
|
||||||
generate_reboot_hint_marker() { | ||||||
local -i reboot_hint=0 | ||||||
local -i retval=0 | ||||||
|
||||||
# shellcheck disable=SC2155 | ||||||
local post_restart_services=$($NEEDS_RESTARTING_COMMAND -s | xargs) | ||||||
local failed_services=() | ||||||
for SERVICE in $post_restart_services; do | ||||||
|
@@ -106,6 +160,8 @@ | |||||
fi | ||||||
done | ||||||
|
||||||
count_post_restart_health || retval=$? | ||||||
|
||||||
local reboothint_separator="" | ||||||
|
||||||
# Consistency is key, that's why the output of needs-restarting --reboothint has different styles for yum & dnf (output for glibc): | ||||||
|
@@ -117,11 +173,12 @@ | |||||
reboothint_separator="*" | ||||||
else | ||||||
CRIT "ERROR: Could not determine OS. I won't create a reboot hint marker" | ||||||
exit 1 | ||||||
return 1 | ||||||
fi | ||||||
|
||||||
# Those are the packages `needs-restarting` is scanning for. We're going to ignore the one's we know we can't restart | ||||||
# ['kernel', 'kernel-rt', 'glibc', 'linux-firmware', 'systemd', 'udev', 'openssl-libs', 'gnutls', 'dbus'] | ||||||
# shellcheck disable=SC2155 | ||||||
local updated_components=$($NEEDS_RESTARTING_COMMAND --reboothint | grep -v "glibc\|systemd\|openssl-libs\|gnutls\|dbus\|udev" | grep -- "${reboothint_separator}") | ||||||
# At this point $updated_components should only report in case kernel* or linux-* was updated. | ||||||
|
||||||
|
@@ -130,6 +187,19 @@ | |||||
DBG "Encountered updates we cannot restart without a reboot: $updated_components" | ||||||
fi | ||||||
|
||||||
if [[ "$PRE_RESTART_HEALTHY" != "$POST_RESTART_HEALTHY" ]]; then | ||||||
reboot_hint=1 | ||||||
# shellcheck disable=SC2048 | ||||||
for SERVICE in ${SERVICES[*]}; do | ||||||
$SYSCTL_COMMAND status "$SERVICE" | ||||||
|
||||||
if [[ $? != 0 ]]; then | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
|
||||||
CRIT "Service \"${SERVICE}\" failed to start again." | ||||||
fi | ||||||
done | ||||||
fi | ||||||
|
||||||
|
||||||
if [[ $reboot_hint == 1 ]]; then | ||||||
mkdir -p "$REBOOT_HINT_PATH" | ||||||
|
@@ -144,9 +214,11 @@ | |||||
} | ||||||
|
||||||
if [[ -z "$IS_TESTING" ]]; then | ||||||
assert_root | ||||||
assemble_service_list | ||||||
count_pre_restart_health | ||||||
execute_pre_hooks | ||||||
restart_services | ||||||
execute_post_hooks | ||||||
generate_reboot_hint_marker | ||||||
fi | ||||||
generate_reboot_hint_marker || exit $? | ||||||
fi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
.PHONY: all | ||
|
||
all: | ||
./test-common.sh | ||
./test-reboot-hint.sh | ||
./test-hooks.sh | ||
./test-restart.sh |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,78 @@ | ||
#!/usr/bin/env bash | ||
|
||
SERVICE_STATUS_RUNNING="● chronicled.service - chronicled | ||
Loaded: loaded (/usr/lib/systemd/system/chronicled.service; enabled; vendor preset: disabled) | ||
Active: active (running) since Thu 2023-11-16 09:22:15 CET; 2 weeks 1 days ago | ||
Main PID: 10200 (chronicled) | ||
Tasks: 37 | ||
Memory: 256.7M | ||
CGroup: /system.slice/chronicled.service | ||
└─10200 /usr/local/chronicle/sbin/chronicled | ||
|
||
Dec 01 10:06:19 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:4] Unknow...it' | ||
Dec 01 10:06:19 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:5] Unknow...it' | ||
Dec 01 10:06:19 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:4] Unknow...it' | ||
Dec 01 10:06:19 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:5] Unknow...it' | ||
Dec 01 10:29:42 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:4] Unknow...it' | ||
Dec 01 10:29:42 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:5] Unknow...it' | ||
Dec 01 10:29:42 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:4] Unknow...it' | ||
Dec 01 10:29:42 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:5] Unknow...it' | ||
Dec 01 10:29:42 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:4] Unknow...it' | ||
Dec 01 10:29:42 HOST systemd[1]: [/usr/lib/systemd/system/chronicled.service:5] Unknow...it' | ||
Hint: Some lines were ellipsized, use -l to show in full. | ||
" | ||
|
||
SERVICE_STATUS_FAILED="● network.service - LSB: Bring up/down networking | ||
Loaded: loaded (/etc/rc.d/init.d/network; bad; vendor preset: disabled) | ||
Active: failed (Result: timeout) since Thu 2023-11-16 09:22:14 CET; 2 weeks 1 days ago | ||
Docs: man:systemd-sysv-generator(8) | ||
CGroup: /system.slice/network.service | ||
├─10737 /sbin/dhclient -q -lf /var/lib/dhclient/dhclient--eth0.lease -pf /var/run/dhclient-eth0.pid -H dev-dsk-suschako-1a-... | ||
└─10789 /sbin/dhclient -6 -nw -lf /var/lib/dhclient/dhclient6--eth0.lease -pf /var/run/dhclient6-eth0.pid eth0 -H dev-dsk-s... | ||
|
||
Dec 01 10:46:41 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10789]: XMT: Solicit on eth0, interval 123790ms. | ||
Dec 01 10:48:45 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10789]: XMT: Solicit on eth0, interval 110330ms. | ||
Dec 01 10:50:35 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10789]: XMT: Solicit on eth0, interval 124670ms. | ||
Dec 01 10:52:40 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10789]: XMT: Solicit on eth0, interval 118210ms. | ||
Dec 01 10:54:38 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10789]: XMT: Solicit on eth0, interval 130040ms. | ||
Dec 01 10:56:48 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10789]: XMT: Solicit on eth0, interval 125680ms. | ||
Dec 01 10:58:01 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10737]: DHCPREQUEST on eth0 to 10.15.96.1 port 67 (xid=0...74) | ||
Dec 01 10:58:01 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10737]: DHCPACK from 10.15.96.1 (xid=0x66783e74) | ||
Dec 01 10:58:01 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10737]: bound to 10.15.105.243 -- renewal in 1676 seconds. | ||
Dec 01 10:58:54 dev-dsk-suschako-1a-32125e6f.eu-west-1.amazon.com dhclient[10789]: XMT: Solicit on eth0, interval 130260ms. | ||
Hint: Some lines were ellipsized, use -l to show in full. | ||
" | ||
|
||
|
||
|
||
DBG() { [[ "$DEBUG" != "" ]] && >&2 echo "$@"; } | ||
|
||
DBG "systemctl-mock invoced with: ${@}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
if [[ "$1" == "daemon-reexec" ]]; then | ||
[[ $# == 1 ]] && exit 0 | ||
[[ "$DEBUG" != "" ]] && echo "systemd daemon-reexec called incorrectly: (No params: $# -> $@)" | ||
DBG "systemd daemon-reexec called incorrectly: (No params: $# -> $@)" | ||
ThatStasGuy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
exit 1 | ||
elif [[ "$1" == "restart" ]]; then | ||
[[ "$DEBUG" != "" ]] && echo "(No. params: $# -> ${@})" | ||
if [[ $SYS_EXPECT_2 == 1 ]]; then | ||
[[ $# == 3 ]] && [[ "$2" == "dummy.service" ]] && [[ "$3" == "dummy2.service" ]] && exit 0 | ||
|
||
exit 98 | ||
elif [[ $SYS_EXPECT_1 == 1 ]]; then | ||
[[ $# == 2 ]] && [[ "$2" == "dummy2.service" ]] && exit 0 | ||
|
||
exit 98 | ||
elif [[ $SYS_EXPECT_0 == 1 ]]; then | ||
[[ $# == 1 ]] && exit 0; | ||
else | ||
exit 98 | ||
fi | ||
elif [[ "$1" == "status" ]]; then | ||
if [[ $SYS_RESTART_FAILED == "1" ]]; then | ||
echo "$SERVICE_STATUS_FAILED" | ||
exit 3 | ||
else | ||
echo "$SERVICE_STATUS_RUNNING" | ||
exit 0 | ||
fi | ||
else | ||
echo "systemd called incorrectly: (No params: $# -> $@)" | ||
exit 1 | ||
DBG "systemd called incorrectly: (No params: $# -> $@)" | ||
ThatStasGuy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fi | ||
|
||
exit 98 | ||
exit 98 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,22 +5,23 @@ | |
# This file needs to be sourced in all tests. Additionally, `TEST_NAME` can be set: | ||
# TEST_NAME="MY NEW TEST" | ||
# . "$(pwd)"/setup_test | ||
# Also, to reset the state before test execution, call reset_test_environment in every test. | ||
|
||
RED='\033[1;91m' | ||
GREEN='\033[1;92m' | ||
YELLOW='\033[1;93m' | ||
BLUE='\033[1;94m' | ||
Check warning on line 13 in tests/setup_test GitHub Actions / shellcheck
|
||
PURPLE='\033[1;95m' | ||
Check warning on line 14 in tests/setup_test GitHub Actions / shellcheck
|
||
WHITE='\033[1;97m' | ||
Check warning on line 15 in tests/setup_test GitHub Actions / shellcheck
|
||
|
||
COLOR_OFF='\033[0m' | ||
|
||
UUT=../bin/smart-restart.sh | ||
export CONF_PATH="$(pwd)"/conf | ||
Check warning on line 20 in tests/setup_test GitHub Actions / shellcheck
|
||
export NEEDS_RESTARTING_COMMAND="$(pwd)"/mocks/needs-restarting | ||
Check warning on line 21 in tests/setup_test GitHub Actions / shellcheck
|
||
export SYSCTL_COMMAND="$(pwd)"/mocks/systemctl | ||
Check warning on line 22 in tests/setup_test GitHub Actions / shellcheck
|
||
export IS_TESTING="1" | ||
export REBOOT_HINT_PATH="$(pwd)" | ||
Check warning on line 24 in tests/setup_test GitHub Actions / shellcheck
|
||
|
||
TEST_NAME="${TEST_NAME:-}" | ||
|
||
|
@@ -28,12 +29,22 @@ | |
|
||
. $UUT | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
# We're testing here sourced bash scripts, global variables keep their values in between tests. | ||
# reset_test_environment resets them so every test starts from a clean state | ||
reset_test_environment() { | ||
SERVICES=() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
BLOCKED_SERVICES=() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
PRE_RESTART_HEALTHY="0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
POST_RESTART_HEALTHY="0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
echo "" > conf/default-denylist | ||
echo "" > conf/custom-denylist | ||
rm -rf "$(pwd)/reboot-hint-marker" | ||
} | ||
|
||
PASSED() { | ||
echo -e " test ${TEST_NAME} [${GREEN}PASSED${COLOR_OFF}]: $1" | ||
} | ||
|
||
FAILED() { | ||
echo -e " test ${TEST_NAME} [${RED}FAILED${COLOR_OFF}]: $1" | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#!/usr/bin/env bash | ||
|
||
# This is the place to test common functionality not suitable for any other tests AND | ||
# not suiteable for an own test-file. | ||
|
||
# cannot follow "$(pwd)/setup_test" | ||
# shellcheck disable=SC1091 | ||
|
||
# Unused variables like TEST_NAME | ||
# shellcheck disable=SC2034 | ||
TEST_NAME="Common" | ||
. "$(pwd)"/setup_test | ||
|
||
function test_assert_root() { | ||
DESCRIPTION="Root assert fails for user" | ||
reset_test_environment | ||
# Need a subshell here since assert_root exits instead of returning | ||
(assert_root) || retval=$? | ||
|
||
if [[ $retval != 0 ]]; then | ||
PASSED "$DESCRIPTION" | ||
else | ||
FAILED "$DESCRIPTION (error: $retval)" | ||
fi | ||
} | ||
|
||
test_assert_root |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 [shellcheck] reported by reviewdog 🐶
Use find instead of ls to better handle non-alphanumeric filenames. SC2012