From 0fdc81bf3cda16165ba2ccc40e893fdeca0abe6b Mon Sep 17 00:00:00 2001 From: Shraddha Agrawal Date: Tue, 6 Jan 2026 18:21:01 +0530 Subject: [PATCH] cephadm: add osd_type to orchestrator This commit enables us to deploy both classic and crimson type OSDs using cephadm. To enable the same, a new feature, osd_type is added to DriverGroupSpec. The default value for the same is classic, but can also be set to crimson. When this value is read by cephadm, the entrypoint is changed from /usr/bin/ceph-osd to /usr/bin/ceph-osd-crimson. Fixes: https://tracker.ceph.com/issues/74081 Signed-off-by: Shraddha Agrawal --- src/cephadm/cephadmlib/daemons/ceph.py | 9 +++++++++ src/pybind/mgr/cephadm/services/osd.py | 2 ++ src/pybind/mgr/cephadm/tests/test_spec.py | 1 + src/pybind/mgr/orchestrator/module.py | 12 ++++++++---- .../mgr/orchestrator/tests/test_orchestrator.py | 1 + .../ceph/deployment/drive_group.py | 17 +++++++++++++++++ .../ceph/tests/test_service_spec.py | 1 + 7 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/cephadm/cephadmlib/daemons/ceph.py b/src/cephadm/cephadmlib/daemons/ceph.py index ac16bbebcfc..ea359d73ed7 100644 --- a/src/cephadm/cephadmlib/daemons/ceph.py +++ b/src/cephadm/cephadmlib/daemons/ceph.py @@ -332,6 +332,15 @@ class OSD(Ceph): def osd_fsid(self) -> Optional[str]: return self._osd_fsid + def default_entrypoint(self) -> str: + config_json = fetch_configs(self.ctx) + if ( + config_json is not None + and config_json.get('osd_type') == 'crimson' + ): + return '/usr/bin/ceph-osd-crimson' + return '/usr/bin/ceph-osd' + @register_daemon_form class CephExporter(ContainerDaemonForm): diff --git a/src/pybind/mgr/cephadm/services/osd.py b/src/pybind/mgr/cephadm/services/osd.py index 60a399149f9..855dc6286ef 100644 --- a/src/pybind/mgr/cephadm/services/osd.py +++ b/src/pybind/mgr/cephadm/services/osd.py @@ -404,6 +404,8 @@ class OSDService(CephService): if hasattr(svc_spec, 'objectstore') and svc_spec.objectstore: config['objectstore'] = svc_spec.objectstore + if hasattr(svc_spec, 'osd_type') and svc_spec.osd_type: + config['osd_type'] = svc_spec.osd_type return config, parent_deps diff --git a/src/pybind/mgr/cephadm/tests/test_spec.py b/src/pybind/mgr/cephadm/tests/test_spec.py index c90b1e7ae79..6f5a41b7f06 100644 --- a/src/pybind/mgr/cephadm/tests/test_spec.py +++ b/src/pybind/mgr/cephadm/tests/test_spec.py @@ -133,6 +133,7 @@ def test_spec_octopus(spec_json): converted = convert_to_old_style_json(spec.to_json()) if spec_json.get('service_type') == 'osd': spec_json['termination_grace_period_seconds'] = 30 + spec_json['osd_type'] = "classic" assert spec_json == converted diff --git a/src/pybind/mgr/orchestrator/module.py b/src/pybind/mgr/orchestrator/module.py index b570e8ced27..9bbc29a358e 100644 --- a/src/pybind/mgr/orchestrator/module.py +++ b/src/pybind/mgr/orchestrator/module.py @@ -16,7 +16,7 @@ except ImportError: natsorted = sorted # type: ignore from ceph.deployment.inventory import Device # noqa: F401; pylint: disable=unused-variable -from ceph.deployment.drive_group import DriveGroupSpec, DeviceSelection, OSDMethod +from ceph.deployment.drive_group import DriveGroupSpec, DeviceSelection, OSDMethod, OSDType from ceph.deployment.service_spec import PlacementSpec, ServiceSpec, service_spec_allow_invalid_from_json, TracingSpec from ceph.deployment.hostspec import SpecValidationError from ceph.deployment.utils import unwrap_ipv6 @@ -1474,7 +1474,8 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, dry_run: bool = False, no_overwrite: bool = False, method: Optional[OSDMethod] = None, - inbuf: Optional[str] = None # deprecated. Was deprecated before Quincy + inbuf: Optional[str] = None, # deprecated. Was deprecated before Quincy + osd_type: Optional[OSDType] = None ) -> HandleCommandResult: """ Create OSD daemon(s) on all available devices @@ -1517,7 +1518,8 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, data_devices=DeviceSelection(all=True), unmanaged=unmanaged, preview_only=dry_run, - method=method + method=method, + osd_type=osd_type ) ] return self._apply_misc(dg_specs, dry_run, format, no_overwrite) @@ -1528,7 +1530,8 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, def _daemon_add_osd(self, svc_arg: Optional[str] = None, method: Optional[OSDMethod] = None, - skip_validation: bool = False) -> HandleCommandResult: + skip_validation: bool = False, + osd_type: Optional[OSDType] = None) -> HandleCommandResult: """Create OSD daemon(s) on specified host and device(s) (e.g., ceph orch daemon add osd myhost:/dev/sdb)""" # Create one or more OSDs""" @@ -1577,6 +1580,7 @@ Usage: drive_group = DriveGroupSpec( placement=PlacementSpec(host_pattern=host_name), method=method, + osd_type=osd_type, **drive_group_spec, ) except (TypeError, KeyError, ValueError) as e: diff --git a/src/pybind/mgr/orchestrator/tests/test_orchestrator.py b/src/pybind/mgr/orchestrator/tests/test_orchestrator.py index 5448239215e..53c47ea8bfe 100644 --- a/src/pybind/mgr/orchestrator/tests/test_orchestrator.py +++ b/src/pybind/mgr/orchestrator/tests/test_orchestrator.py @@ -172,6 +172,7 @@ def test_orch_ls(_describe_service): spec: filter_logic: AND objectstore: bluestore + osd_type: classic termination_grace_period_seconds: 30 status: running: 123 diff --git a/src/python-common/ceph/deployment/drive_group.py b/src/python-common/ceph/deployment/drive_group.py index a4fae2c93bd..a40cada7e46 100644 --- a/src/python-common/ceph/deployment/drive_group.py +++ b/src/python-common/ceph/deployment/drive_group.py @@ -24,6 +24,14 @@ class OSDMethod(str, enum.Enum): return self.value +class OSDType(str, enum.Enum): + crimson = 'crimson' + classic = 'classic' + + def to_json(self) -> str: + return self.value + + class DeviceSelection(object): """ Used within :class:`ceph.deployment.drive_group.DriveGroupSpec` to specify the devices @@ -173,6 +181,7 @@ class DriveGroupSpec(ServiceSpec): "journal_size", "unmanaged", "filter_logic", "preview_only", "extra_container_args", "extra_entrypoint_args", "data_allocate_fraction", "method", "termination_grace_period_seconds", "crush_device_class", "config", + "osd_type", ] def __init__(self, @@ -204,6 +213,7 @@ class DriveGroupSpec(ServiceSpec): config=None, # type: Optional[Dict[str, str]] custom_configs=None, # type: Optional[List[CustomConfig]] crush_device_class=None, # type: Optional[str] + osd_type=None, # type: Optional[OSDType] termination_grace_period_seconds: Optional[int] = 30, ): assert service_type is None or service_type == 'osd' @@ -281,6 +291,9 @@ class DriveGroupSpec(ServiceSpec): #: Crush device class to assign to OSDs self.crush_device_class = crush_device_class + #: OSD type to install, defaults to classic OSDs if not specified + self.osd_type = osd_type if osd_type is not None else "classic" + @classmethod def _from_json_impl(cls, json_drive_group): # type: (dict) -> DriveGroupSpec @@ -388,6 +401,10 @@ class DriveGroupSpec(ServiceSpec): for device in list(self.data_devices.paths): if not device.path: raise DriveGroupValidationError(self.service_id, 'Device path cannot be empty') # noqa E501 + if self.osd_type not in ['classic', 'crimson']: + raise DriveGroupValidationError( + self.service_id, + 'osd_type must be one of classic, crimson') yaml.add_representer(DriveGroupSpec, DriveGroupSpec.yaml_representer) diff --git a/src/python-common/ceph/tests/test_service_spec.py b/src/python-common/ceph/tests/test_service_spec.py index ab3c1f98884..b4c168e89e2 100644 --- a/src/python-common/ceph/tests/test_service_spec.py +++ b/src/python-common/ceph/tests/test_service_spec.py @@ -356,6 +356,7 @@ spec: wal_devices: model: NVME-QQQQ-987 termination_grace_period_seconds: 30 + osd_type: classic --- service_type: alertmanager service_name: alertmanager -- 2.47.3