fix(reliability): clear boot marker on graceful shutdown (I1)
This commit is contained in:
@@ -5106,6 +5106,17 @@ def check_boot_marker():
|
||||
return False
|
||||
|
||||
|
||||
def _clear_boot_marker():
|
||||
"""Best-effort: a clean shutdown must not read as an unexpected reboot."""
|
||||
marker = globals().get('BOOT_MARKER')
|
||||
if not marker:
|
||||
return
|
||||
try:
|
||||
os.unlink(marker)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def startup_env_check(attempts=STARTUP_CHECK_ATTEMPTS,
|
||||
delay=STARTUP_CHECK_DELAY):
|
||||
"""Run and print the startup contract, allowing boot dependencies time.
|
||||
@@ -7143,6 +7154,10 @@ def _request_shutdown(signum=None, frame=None):
|
||||
LIVE_STOP.set()
|
||||
HEALTH_STOP.set()
|
||||
_recon_hopper_stop.set()
|
||||
try:
|
||||
_clear_boot_marker()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _uci_iface_present(name):
|
||||
|
||||
@@ -63,6 +63,47 @@ class ReliabilityApiTest(unittest.TestCase):
|
||||
os.unlink(marker)
|
||||
server.BOOT_MARKER = old
|
||||
|
||||
def test_clean_cycle_boot_shutdown_next_boot_not_unexpected(self):
|
||||
import tempfile
|
||||
import threading
|
||||
import mk8_events as events_mod
|
||||
marker = tempfile.mktemp()
|
||||
old = (server.BOOT_MARKER, server.LIVE_STOP, server.HEALTH_STOP,
|
||||
server._recon_hopper_stop, events_mod.mark_boot)
|
||||
stops = (threading.Event(), threading.Event(), threading.Event())
|
||||
server.BOOT_MARKER = marker
|
||||
server.LIVE_STOP, server.HEALTH_STOP, \
|
||||
server._recon_hopper_stop = stops
|
||||
booted = []
|
||||
events_mod.mark_boot = \
|
||||
lambda unexpected=False: booted.append(unexpected)
|
||||
try:
|
||||
# Simulate a previous run's marker left behind: boot is unexpected.
|
||||
open(marker, 'w').write('0')
|
||||
self.assertTrue(server.check_boot_marker())
|
||||
self.assertEqual(booted, [True])
|
||||
# Clean shutdown clears the marker...
|
||||
self.assertTrue(os.path.exists(marker))
|
||||
server._request_shutdown()
|
||||
self.assertFalse(os.path.exists(marker),
|
||||
'graceful shutdown must clear the boot marker')
|
||||
for ev in stops:
|
||||
self.assertTrue(ev.is_set())
|
||||
# ...so the next boot is clean and re-arms the marker.
|
||||
self.assertFalse(server.check_boot_marker())
|
||||
self.assertEqual(booted[-1], False)
|
||||
self.assertTrue(os.path.exists(marker))
|
||||
# _clear_boot_marker is best-effort on missing/None markers.
|
||||
server._clear_boot_marker()
|
||||
self.assertFalse(os.path.exists(marker))
|
||||
server.BOOT_MARKER = None
|
||||
server._clear_boot_marker()
|
||||
finally:
|
||||
(server.BOOT_MARKER, server.LIVE_STOP, server.HEALTH_STOP,
|
||||
server._recon_hopper_stop, events_mod.mark_boot) = old
|
||||
if os.path.exists(marker):
|
||||
os.unlink(marker)
|
||||
|
||||
def test_profile_routes_registered(self):
|
||||
handler, _ = server.ROUTER.dispatch('GET',
|
||||
'/api/reliability/profiles')
|
||||
|
||||
Reference in New Issue
Block a user