From: Shraddha Agrawal Date: Tue, 6 Jan 2026 12:51:01 +0000 (+0530) Subject: cephadm: add osd_type to orchestrator X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=0fdc81bf3cda16165ba2ccc40e893fdeca0abe6b;p=ceph.git 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 --- diff --git a/src/cephadm/cephadmlib/daemons/ceph.py b/src/cephadm/cephadmlib/daemons/ceph.py index ac16bbebcfcc..ea359d73ed77 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 60a399149f9f..855dc6286ef1 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 c90b1e7ae793..6f5a41b7f062 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 b570e8ced27f..9bbc29a358e8 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 5448239215e0..53c47ea8bfea 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 a4fae2c93bd8..a40cada7e46e 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 ab3c1f988843..b4c168e89e25 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