fix(reliability): encode str stdin in device_run; smoke drill path fixes + regression tests
This commit is contained in:
@@ -107,6 +107,8 @@ SELF_PAYLOAD_KEY = os.environ.get('PAGER_SELF_PAYLOAD_KEY', 'user~remote_access~
|
||||
|
||||
def device_run(args, timeout=20, input_data=None):
|
||||
try:
|
||||
if isinstance(input_data, str):
|
||||
input_data = input_data.encode('utf-8')
|
||||
p = subprocess.run(args, input=input_data, capture_output=True, timeout=timeout)
|
||||
return p.returncode, p.stdout.decode('utf-8', 'replace'), p.stderr.decode('utf-8', 'replace')
|
||||
except FileNotFoundError:
|
||||
|
||||
+22
-7
@@ -39,6 +39,9 @@ set -u
|
||||
|
||||
BASE=/mmc/mk8
|
||||
REL="$BASE/releases/current"
|
||||
# Release layout: <release>/user/<category>/<key>/... — resolve the payload dir.
|
||||
REL_PAY="$(find "$REL/user" -maxdepth 3 -name server.py 2>/dev/null | head -n 1)"
|
||||
REL_PAY="${REL_PAY%/server.py}"
|
||||
LEGACY=/root/payloads/user/remote_access/pager-webui
|
||||
URL=http://127.0.0.1:8080
|
||||
GUARD_INIT=/etc/init.d/mk8-guard
|
||||
@@ -221,9 +224,9 @@ check_monitors() {
|
||||
}
|
||||
|
||||
check_versions() {
|
||||
sv="$(grep '^SERVER_VERSION' "$REL/server.py" 2>/dev/null | head -n 1 \
|
||||
sv="$(grep '^SERVER_VERSION' "$REL_PAY/server.py" 2>/dev/null | head -n 1 \
|
||||
| sed -e 's/^SERVER_VERSION = //' -e "s/'//g" | tr -d '\r')"
|
||||
pv="$(grep '^#[ ]*[Vv]ersion:' "$REL/payload.sh" 2>/dev/null | head -n 1 \
|
||||
pv="$(grep '^#[ ]*[Vv]ersion:' "$REL_PAY/payload.sh" 2>/dev/null | head -n 1 \
|
||||
| sed 's/^#[ ]*[Vv]ersion:[ ]*//' | tr -d '\r')"
|
||||
if [ -n "$sv" ] && [ "$sv" = "$pv" ]; then
|
||||
pass "versions: release server.py and payload.sh agree ($sv)"
|
||||
@@ -241,7 +244,7 @@ check_authed_api() {
|
||||
fail 'authed API: python3 not found for response check'
|
||||
return
|
||||
fi
|
||||
body='{"password":"'"$PASS"'"}'
|
||||
body='{"username":"root","password":"'"$PASS"'"}'
|
||||
code="$(curl -fsS -m 10 -o /dev/null -w '%{http_code}' \
|
||||
-c "$JAR" -H 'Content-Type: application/json' \
|
||||
-d "$body" "$URL/api/login" 2>/dev/null)"
|
||||
@@ -272,7 +275,7 @@ drill_bad_values() {
|
||||
|
||||
uci set pineapd.wlan1mon.bands='2,5'
|
||||
uci commit pineapd
|
||||
"$PY" "$REL/server.py" --reconcile >/dev/null 2>&1
|
||||
"$PY" "$REL_PAY/server.py" --reconcile >/dev/null 2>&1
|
||||
got="$(uci_get pineapd.wlan1mon.bands)"
|
||||
if [ "$got" = "5" ]; then
|
||||
pass 'drill: reconcile repaired bands 2,5 -> 5'
|
||||
@@ -289,7 +292,7 @@ drill_bad_values() {
|
||||
done
|
||||
uci set "pineapd.@ssidpool[0].ssid=${list# }"
|
||||
uci commit pineapd
|
||||
"$PY" "$REL/server.py" --reconcile >/dev/null 2>&1
|
||||
"$PY" "$REL_PAY/server.py" --reconcile >/dev/null 2>&1
|
||||
got="$(uci_get 'pineapd.@ssidpool[0].ssid')"
|
||||
if [ -z "$got" ]; then
|
||||
pass 'drill: reconcile cleared oversized SSID pool'
|
||||
@@ -303,7 +306,7 @@ drill_bad_values() {
|
||||
uci -q delete 'pineapd.@ssidpool[0].ssid'
|
||||
fi
|
||||
uci commit pineapd
|
||||
"$PY" "$REL/server.py" --reconcile >/dev/null 2>&1
|
||||
"$PY" "$REL_PAY/server.py" --reconcile >/dev/null 2>&1
|
||||
}
|
||||
|
||||
drill_role() {
|
||||
@@ -368,12 +371,24 @@ PYEOF
|
||||
}
|
||||
|
||||
drill_watchdog() {
|
||||
WDOG="$REL/mk8-watchdog.sh"
|
||||
WDOG="$REL_PAY/mk8-watchdog.sh"
|
||||
[ -f "$WDOG" ] || WDOG="$LEGACY/mk8-watchdog.sh"
|
||||
if [ ! -f "$WDOG" ]; then
|
||||
fail 'drill: mk8-watchdog.sh not found in release or legacy dir'
|
||||
return
|
||||
fi
|
||||
# Ensure a profile exists: snapshot the live config as the drill target.
|
||||
if [ ! -d "$BASE/profiles" ] || [ -z "$(ls "$BASE/profiles" 2>/dev/null)" ]; then
|
||||
"$PY" - "$REL_PAY" <<'PYEOF' >/dev/null 2>&1 || {
|
||||
import sys
|
||||
sys.path.insert(0, sys.argv[1])
|
||||
import mk8_profiles
|
||||
mk8_profiles.snapshot('smoke-drill')
|
||||
PYEOF
|
||||
fail 'drill: could not snapshot a profile for watchdog drill'
|
||||
return
|
||||
}
|
||||
fi
|
||||
prof=lastknown-good
|
||||
[ -d "$BASE/profiles/$prof" ] \
|
||||
|| prof="$(ls "$BASE/profiles" 2>/dev/null | head -n 1)"
|
||||
|
||||
@@ -69,3 +69,15 @@ class DeviceRunTest(unittest.TestCase):
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
|
||||
class DeviceRunInputTest(unittest.TestCase):
|
||||
def test_str_input_data_is_encoded(self):
|
||||
rc, out, err = server.device_run(['cat'], input_data='uci import text')
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertEqual(out, 'uci import text')
|
||||
|
||||
def test_bytes_input_data_passes_through(self):
|
||||
rc, out, err = server.device_run(['cat'], input_data=b'raw')
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertEqual(out, 'raw')
|
||||
|
||||
Reference in New Issue
Block a user