Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a29f79f
feat(systemd): rate system health incl. crash-loop detection
JanZachmann Jul 27, 2026
0170c77
fix(update_validation): poll system health instead of broken state wait
JanZachmann Jul 27, 2026
75caef3
feat(healthcheck): rate crash-looping services as red
JanZachmann Jul 27, 2026
c0d49c5
fix(healthcheck): rate failed service listing as red
JanZachmann Jul 27, 2026
dc9281a
chore: document system health validation; bump to 0.45.0
JanZachmann Jul 27, 2026
1248f3c
docs: correct crash-loop wording
JanZachmann Jul 27, 2026
b9f18de
fix(update_validation): flag crash loops by restart count only
JanZachmann Jul 27, 2026
523e7fb
fix(healthcheck): address review findings
JanZachmann Jul 29, 2026
be42145
fix(update_validation): derive health deadline from remaining time
JanZachmann Jul 30, 2026
8e267a4
fix(healthcheck): rate only a live crash loop red
JanZachmann Jul 30, 2026
a086e99
revert(healthcheck): keep the double underscore in check script names
JanZachmann Jul 30, 2026
c6e07bd
fix(update_validation): do not confirm health while a restart is pending
JanZachmann Jul 30, 2026
3db1212
fix(update_validation): reject a crash loop threshold of 0
JanZachmann Jul 30, 2026
4ec4b2e
fix(update_validation): confirm an unhealthy verdict before rolling back
JanZachmann Jul 30, 2026
b31c1bb
fix(update_validation): decide the deadline by all observations
JanZachmann Jul 31, 2026
9029c26
fix(update_validation): tolerate a transient system health poll error
JanZachmann Jul 31, 2026
4b6a329
fix(update_validation): rate only an auto-restart cycle as a pending …
JanZachmann Jul 31, 2026
2367e7a
test(systemd): restore the crash loop threshold env var on a panic
JanZachmann Jul 31, 2026
f9ee5cc
fix(update_validation): read the unit states as strings
JanZachmann Jul 31, 2026
7038345
fix(update_validation): let a healthy observation count at the deadline
JanZachmann Jul 31, 2026
7e97bc7
fix(update_validation): keep the poll error cause in the reboot reason
JanZachmann Jul 31, 2026
ace715e
fix(update_validation): report the cause seen most often
JanZachmann Jul 31, 2026
e792625
fix(healthcheck): rate a queued restart as a crash loop too
JanZachmann Jul 31, 2026
fb6ec7c
docs(update_validation): describe the deadline rules as they are now
JanZachmann Jul 31, 2026
5e476fd
docs(update_validation): record the cause tie-break and the failed po…
JanZachmann Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
name = "omnect-device-service"
readme = "README.md"
repository = "https://github.com/omnect/omnect-device-service.git"
version = "0.44.1"
version = "0.45.0"

[dependencies]
actix-server = { version = "2.6", default-features = false }
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,12 @@ curl -X POST --unix-socket /run/omnect-device-service/api.sock http://localhost/
curl -X POST --unix-socket /run/omnect-device-service/api.sock http://localhost/healthcheck/v1
```

Independent of this endpoint, the [healthcheck](healthcheck/) directory contains
scripts that check specific system functions and rate each one green, yellow, or
red. `omnect_health_check.sh` runs the checks configured in
`omnect_health_checks.json` and derives the script name from each entry's type,
so the configuration file lists what a device actually checks.

### Status updates

omnect-device-service is capable to publish certain properties to a list of defined endpoints. Currently the following properties are published:
Expand Down
73 changes: 73 additions & 0 deletions healthcheck/omnect_health__crash_loop.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/bin/sh
Comment thread
JoergZeidler marked this conversation as resolved.
#

. healthchecklib.sh

# prints crash-looping services to stdout; returns 1 if they cannot be determined
function find_crash_loops() {
Comment thread
HarryWaschkeit marked this conversation as resolved.
local unit props active sub found="" units

units=$(systemctl list-units --all --type=service --no-legend --plain | awk '{print $1}')
if [ -z "${units}" ]; then
return 1
fi
Comment thread
JoergZeidler marked this conversation as resolved.

for unit in ${units}; do
props=$(systemctl show "${unit}" -p ActiveState,SubState 2>/dev/null) || continue
active=$(echo "${props}" | sed -n 's/^ActiveState=//p')
sub=$(echo "${props}" | sed -n 's/^SubState=//p')

# only a live loop is rated red: NRestarts has no time window and keeps
# counting occasional restarts, and a unit that gave up restarting shows
# up as a failed unit in the system-running check
if [ "${active}" = "activating" ]; then
case "${sub}" in
# 'auto-restart-queued' is the same pending restart with the
# restart job already queued
auto-restart|auto-restart-queued)
found="${found} ${unit}(${sub})"
;;
esac
fi
done

echo "${found}"
}

function do_check() {
local found rating=0

found=$(find_crash_loops) || rating=2
[ -z "${found}" ] || rating=2
print_rating ${rating} crash_loop "$ME"
do_rate ${rating}
return ${rating}
}

function do_get_infos() {
local found rating=0 error=""

found=$(find_crash_loops) || { rating=2; error="failed to list services"; }
[ -z "${found}" ] || rating=2
print_info_header "${ME}" "${rating}"
[ -z "${error}" ] || echo "${error}"
[ -z "${found}" ] || echo "crash-looping services:${found}"
return ${rating}
}

command="${1:-check}"
[ "$1" ] && shift
check_command_arg "$command"

case "$command" in
check)
do_check "$@"
retval=$?
;;
get-infos)
do_get_infos "$@"
retval=$?
;;
esac

exit $retval
5 changes: 3 additions & 2 deletions healthcheck/omnect_health__system_running.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ function do_get_infos() {
local ret
checkit
ret=$?
# TODO/FIXME: how to find and show reasons for this state?
print_info_header "${ME}" "$ret"
[ $ret = 0 ] || { systemctl is-system-running; systemctl --failed; }
# a state other than "running" comes from failed units or from jobs that
# are still pending
[ $ret = 0 ] || { systemctl is-system-running; systemctl --failed; systemctl list-jobs; }
return $ret
}

Expand Down
4 changes: 4 additions & 0 deletions healthcheck/omnect_health_checks.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
"name": "system_running",
"type": "system_running"
},
{
"name": "crash_loop",
"type": "crash_loop"
},
{
"name": "timesync",
"type": "timesync"
Expand Down
4 changes: 4 additions & 0 deletions healthcheck/omnect_health_checks.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@
"name": "system_running",
"type": "system_running"
},
{
"name": "crash_loop",
"type": "crash_loop"
},
{
"name": "timesync",
"type": "timesync"
Expand Down
Loading
Loading