]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/cephadm: don't treat unknown daemon state as error 68290/head
authorLumir Sliva <61183145+lumir-sliva@users.noreply.github.com>
Thu, 9 Apr 2026 16:14:21 +0000 (18:14 +0200)
committerLumir Sliva <61183145+lumir-sliva@users.noreply.github.com>
Wed, 8 Jul 2026 12:48:12 +0000 (14:48 +0200)
cephadm ls may transiently report state='unknown' for daemons that are
still starting up. The state mapping in _refresh_host_daemons mapped
'unknown' to DaemonDescriptionStatus.error, which caused
update_failed_daemon_health_check to fire CEPHADM_FAILED_DAEMON for
daemons that were simply mid-startup. The warning clears on the next
refresh once the daemon reaches a real state, but it causes spurious
QA failures across many test suites.

Map 'unknown' to DaemonDescriptionStatus.unknown instead — the enum
value already exists and is handled by to_str() and the dashboard.
get_error_daemons() only checks for .error, so unknown daemons no
longer trigger the health warning.

Signed-off-by: Lumir Sliva <61183145+lumir-sliva@users.noreply.github.com>
src/pybind/mgr/cephadm/module.py
src/pybind/mgr/cephadm/tests/test_cephadm.py

index 5fcc4afac0c2c8cc1ec4bd54f5c9fd6b8fafc110..0d0c8988af8d53ef2668513df2c2df11289bb6b9 100644 (file)
@@ -1123,7 +1123,7 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule):
                     'running': DaemonDescriptionStatus.running,
                     'stopped': DaemonDescriptionStatus.stopped,
                     'error': DaemonDescriptionStatus.error,
-                    'unknown': DaemonDescriptionStatus.error,
+                    'unknown': DaemonDescriptionStatus.unknown,
                 }[d['state']]
 
             cached_dd = None
index e2c5f5bc4bde563e5d149e763b16f59e434e386f..f56a2a7619cc65baa39c83f88e5f7cad717adb0f 100644 (file)
@@ -419,6 +419,48 @@ class TestCephadm(object):
             dds = wait(cephadm_module, cephadm_module.list_daemons())
             assert {d.name() for d in dds} == {'rgw.myrgw.foobar', 'haproxy.test.bar'}
 
+    @mock.patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm(
+        json.dumps([
+            dict(
+                name='rgw.myrgw.running',
+                style='cephadm',
+                fsid='fsid',
+                container_id='container_id',
+                state='running',
+            ),
+            dict(
+                name='rgw.myrgw.unknown',
+                style='cephadm',
+                fsid='fsid',
+                container_id='container_id',
+                state='unknown',
+            ),
+            dict(
+                name='rgw.myrgw.error',
+                style='cephadm',
+                fsid='fsid',
+                container_id='container_id',
+                state='error',
+            ),
+        ])
+    ))
+    def test_unknown_state_not_error(self, cephadm_module: CephadmOrchestrator):
+        # Verify that daemons with state='unknown' from cephadm ls are not
+        # treated as errors and do not trigger CEPHADM_FAILED_DAEMON.
+        # See https://tracker.ceph.com/issues/65728
+        cephadm_module.service_cache_timeout = 10
+        with with_host(cephadm_module, 'myhost'):
+            CephadmServe(cephadm_module)._refresh_host_daemons('myhost')
+            dds = {d.name(): d for d in wait(cephadm_module, cephadm_module.list_daemons())}
+            # unknown should map to DaemonDescriptionStatus.unknown, not error
+            assert dds['rgw.myrgw.unknown'].status == DaemonDescriptionStatus.unknown
+            assert dds['rgw.myrgw.error'].status == DaemonDescriptionStatus.error
+            assert dds['rgw.myrgw.running'].status == DaemonDescriptionStatus.running
+            # only the error daemon should appear in get_error_daemons
+            error_names = {d.name() for d in cephadm_module.cache.get_error_daemons()}
+            assert 'rgw.myrgw.error' in error_names
+            assert 'rgw.myrgw.unknown' not in error_names
+
     @mock.patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('[]'))
     def test_daemon_action(self, cephadm_module: CephadmOrchestrator):
         cephadm_module.service_cache_timeout = 10