fix: health monitor detects down monitors via ip link flags + disables wlan2mon

operstate reports 'unknown' on monitors (normal), so _iface_up now parses
admin flags from ip link. Discovered a second pineapd SIGSEGV source: the
wlan2mon 6GHz monitor this hardware never creates, hopping on the missing
iface (~85s crash cadence even with the SSID pool off). The monitor now
disables it in the fix path.
This commit is contained in:
2026-08-18 20:26:16 -05:00
parent 4ce19693d1
commit adfe8f784f
2 changed files with 38 additions and 12 deletions
+9 -6
View File
@@ -15,11 +15,13 @@ class HealthCheckTest(unittest.TestCase):
self.runs = []
self.ping_ok = True
self.sigsegvs = 0
self.iw_out = 'wlan0mon\nwlan1mon\n'
self.iface_up = {'wlan0mon': True, 'wlan1mon': True}
self.uci_state = {}
server._health.update({
'sigsegv_last': None, 'last_fix': 0.0, 'fixes': 0,
'last_action': None, 'pineap_up': False})
self.old_iface_up = server._iface_up
server._iface_up = lambda name: self.iface_up.get(name, True)
def fake_run(args, timeout=20, input_data=None):
self.runs.append((list(args), timeout))
@@ -30,8 +32,6 @@ class HealthCheckTest(unittest.TestCase):
return (1, '', 'could not connect to pineap: connection refused')
if a[0] == 'logread':
return (0, 'SIGSEGV\n' * self.sigsegs if hasattr(self, 'sigsegs') else '', '')
if a[0] == 'iw':
return (0, self.iw_out, '')
if a[:2] == ['uci', 'set']:
k, _, v = a[2].partition('=')
self.uci_state[k] = v
@@ -45,6 +45,9 @@ class HealthCheckTest(unittest.TestCase):
server.device_run = fake_run
def tearDown(self):
server._iface_up = self.old_iface_up
def test_pineap_up_reports_no_action(self):
result = server.health_check()
self.assertTrue(result['pineap_up'])
@@ -66,12 +69,12 @@ class HealthCheckTest(unittest.TestCase):
self.assertEqual(result['last_action'], 'pineapd restart')
self.assertIn(['/etc/init.d/pineapd', 'restart'], [r[0] for r in self.runs])
def test_down_without_crash_brings_monitor_up(self):
def test_down_without_crash_brings_monitors_up(self):
self.ping_ok = False
self.uci_state['pineapd.@ssidpool[0].disable'] = '1'
self.iw_out = 'wlan0mon\n'
self.iface_up = {'wlan0mon': True, 'wlan1mon': False}
result = server.health_check()
self.assertEqual(result['last_action'], 'wlan1mon brought up')
self.assertEqual(result['last_action'], 'monitor interfaces brought up')
self.assertIn(['ip', 'link', 'set', 'wlan1mon', 'up'], [r[0] for r in self.runs])
def test_down_disables_pool_regardless_of_sigsegv_history(self):