]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
cephadm: add osd_type to orchestrator
authorShraddha Agrawal <shraddha.agrawal000@gmail.com>
Tue, 6 Jan 2026 12:51:01 +0000 (18:21 +0530)
committerShraddha Agrawal <shraddha.agrawal000@gmail.com>
Mon, 2 Feb 2026 12:13:35 +0000 (17:43 +0530)
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 <shraddha.agrawal000@gmail.com>
src/cephadm/cephadmlib/daemons/ceph.py
src/pybind/mgr/cephadm/services/osd.py
src/pybind/mgr/cephadm/tests/test_spec.py
src/pybind/mgr/orchestrator/module.py
src/pybind/mgr/orchestrator/tests/test_orchestrator.py
src/python-common/ceph/deployment/drive_group.py
src/python-common/ceph/tests/test_service_spec.py

index ac16bbebcfcc9525998e8d8733b389a1ed6ccd72..ea359d73ed77edebc42aa87effbfe2888a0f731f 100644 (file)
@@ -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):
index 60a399149f9f9377ef77b34409f50ef656bdb9a8..855dc6286ef133edb37db491fd144cea1c77fb0b 100644 (file)
@@ -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
 
 
index c90b1e7ae7930980d2bb8d0a1f72fafd948b3891..6f5a41b7f062dd01465546262cead2ca298dfbaf 100644 (file)
@@ -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
 
 
index b570e8ced27f412c6053fa75e24e71a4927ded11..9bbc29a358e818dac24eea118a34217ca0f5d71a 100644 (file)
@@ -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:
index 5448239215e0a58f6fa89377d1a7fa2f9c669157..53c47ea8bfea24e23828383b3cd86b933364b5ea 100644 (file)
@@ -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
index a4fae2c93bd84119c73939fa30784402c3ba3bdc..a40cada7e46ef0fe87cc42971089acbd71e050da 100644 (file)
@@ -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)
index ab3c1f988843b8130d4d0e8504d9e002ba60a1d3..b4c168e89e254997bfdee78dabfc1441e5b644e7 100644 (file)
@@ -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