From dd7d1196af1e9a318facca3134fc6bdc3f5d5471 Mon Sep 17 00:00:00 2001 From: Joshua Blanch Date: Fri, 25 Apr 2025 21:04:28 +0000 Subject: [PATCH] mgr/cephadm: disallow changing OSD service type to non-OSD types Prevent accidental or invalid service type changes for OSD daemons by enforcing that an OSD's service type cannot be changed to a different service type (e.g., mon, mds, etc.) Fixes: https://tracker.ceph.com/issues/71087 Signed-off-by: Joshua Blanch --- src/pybind/mgr/cephadm/module.py | 6 ++++ src/pybind/mgr/cephadm/tests/test_cephadm.py | 30 ++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/pybind/mgr/cephadm/module.py b/src/pybind/mgr/cephadm/module.py index c1b91abe8f45b..13f9b16a69c04 100644 --- a/src/pybind/mgr/cephadm/module.py +++ b/src/pybind/mgr/cephadm/module.py @@ -4120,6 +4120,12 @@ Then run the following: "Please try again after applying an OSD service that matches " "the service name to which you want to attach OSDs.") + # Verify that service_type is of osd type + spec = self.spec_store[service_name].spec + if spec.service_type != 'osd': + raise OrchestratorError(f"Service '{service_name}' is not an OSD service (type: {spec.service_type}). " + "OSDs can only be assigned to OSD service specs.") + daemons: List[orchestrator.DaemonDescription] = self.cache.get_daemons_by_type('osd') update_osd = defaultdict(list) for daemon in daemons: diff --git a/src/pybind/mgr/cephadm/tests/test_cephadm.py b/src/pybind/mgr/cephadm/tests/test_cephadm.py index 946d165c702cb..50bc6818f0d43 100644 --- a/src/pybind/mgr/cephadm/tests/test_cephadm.py +++ b/src/pybind/mgr/cephadm/tests/test_cephadm.py @@ -2877,3 +2877,33 @@ Traceback (most recent call last): # on nvmeof.foo.foo's daemons nvmeof_bar_blocking_hosts = NvmeofService(cephadm_module).get_blocking_daemon_hosts('nvmeof.bar.bar') assert set([h.hostname for h in nvmeof_bar_blocking_hosts]) == set(['host1', 'host2']) + + @mock.patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('{}')) + @mock.patch("cephadm.inventory.HostCache.get_daemons_by_type") + def test_set_osd_spec_non_osd_service(self, _get_daemons_by_type, cephadm_module): + with with_host(cephadm_module, 'test'): + osd_daemon = DaemonDescription(daemon_type='osd', daemon_id='1', hostname='test') + _get_daemons_by_type.return_value = [osd_daemon] + + mgr_service = ServiceSpec('mgr', placement=PlacementSpec(hosts=['test'])) + + with with_service(cephadm_module, mgr_service): + with pytest.raises(OrchestratorError) as e: + cephadm_module.set_osd_spec('mgr', ['1']) + + assert "Service 'mgr' is not an OSD service (type: mgr). OSDs can only be assigned to OSD service specs." in str(e.value) + + # Move osd.1 to osd.foo service + spec = DriveGroupSpec( + service_id='foo', + placement=PlacementSpec( + host_pattern='*', + ), + data_devices=DeviceSelection( + all=True + ) + ) + c = cephadm_module.apply([spec]) + assert wait(cephadm_module, c) == ['Scheduled osd.foo update...'] + + cephadm_module.set_osd_spec('osd.foo', ['1']) -- 2.39.5