From: Shubha Jain Date: Mon, 16 Mar 2026 11:07:25 +0000 (+0530) Subject: cephadm: fix upgrade order validation when using --daemon-types with --hosts X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4759cad91c5f88b9c5f3ade665f7adfa184cb497;p=ceph.git cephadm: fix upgrade order validation when using --daemon-types with --hosts Fix upgrade validation to check earlier daemon types on both same-host and other-host groups when host filtering is used. Previously only daemons on other hosts were validated, allowing upgrades to bypass the enforced upgrade order in stretch mode clusters. Add regression tests covering daemon_types+hosts and services+hosts scenarios. Fixes: https://tracker.ceph.com/issues/75397 Signed-off-by: Shubha Jain --- diff --git a/src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 b/src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 index 606b1c5704f2..a9758fff578d 100644 --- a/src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 +++ b/src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 @@ -55,6 +55,18 @@ RADOS_URLS { watch_url = "{{ url }}"; } +CEPH { + Ceph_Conf = "/etc/ceph/ceph.conf"; + umask = 0000; + client_oc = false; + async = false; + zerocopy = false; + use_old_uuid = false; + + register_service = true; + nodeid = "{{ nodeid }}"; +} + RGW { cluster = "ceph"; name = "client.{{ rgw_user }}"; diff --git a/src/pybind/mgr/cephadm/tests/test_upgrade.py b/src/pybind/mgr/cephadm/tests/test_upgrade.py index 3b5c305b5f0f..4882c6d27418 100644 --- a/src/pybind/mgr/cephadm/tests/test_upgrade.py +++ b/src/pybind/mgr/cephadm/tests/test_upgrade.py @@ -433,6 +433,30 @@ def test_upgrade_ls(current_version, use_tags, show_all_versions, tags, result, None, False ), + ( # invalid, can't upgrade crash on a while mon on a is not upgraded + [('mgr', 'a', 'a.x')], + [('mon', 'a', 'a'), ('crash', 'a', 'a')], + ['crash'], + ['a'], + None, + True + ), + ( # invalid, can't upgrade crash on a while mgr on a is not upgraded + [('mon', 'a', 'a')], + [('mgr', 'a', 'a.x'), ('crash', 'a', 'a')], + ['crash'], + ['a'], + None, + True + ), + ( # invalid, can't upgrade crash service on a while mon on a is not upgraded + [('mgr', 'a', 'a.x')], + [('mon', 'a', 'a'), ('crash', 'a', 'a')], + None, + ['a'], + ['crash'], + True + ), ] ) @mock.patch("cephadm.module.HostCache.get_daemons") @@ -443,14 +467,14 @@ def test_staggered_upgrade_validation( get_image_info, get_daemons, upgraded: List[Tuple[str, str, str]], - not_upgraded: List[Tuple[str, str, str, str]], + not_upgraded: List[Tuple[str, str, str]], daemon_types: Optional[str], hosts: Optional[str], services: Optional[str], should_block: bool, cephadm_module: CephadmOrchestrator, ): - def to_dds(ts: List[Tuple[str, str]], upgraded: bool) -> List[DaemonDescription]: + def to_dds(ts: List[Tuple[str, str, str]], upgraded: bool) -> List[DaemonDescription]: dds = [] digest = 'new_image@repo_digest' if upgraded else 'old_image@repo_digest' for t in ts: diff --git a/src/pybind/mgr/cephadm/upgrade.py b/src/pybind/mgr/cephadm/upgrade.py index a1842cfdc2ab..407c4587a782 100644 --- a/src/pybind/mgr/cephadm/upgrade.py +++ b/src/pybind/mgr/cephadm/upgrade.py @@ -388,6 +388,11 @@ class CephadmUpgrade: earlier_types = [t for t in earlier_types if t not in dtypes] return [d for d in candidates if d.daemon_type in earlier_types] + def _filter_by_hosts(daemons: List[DaemonDescription], hosts: List[str], on_hosts: bool) -> List[DaemonDescription]: + if on_hosts: + return [d for d in daemons if d.hostname is not None and d.hostname in hosts] + return [d for d in daemons if d.hostname is not None and d.hostname not in hosts] + if self.upgrade_state: raise OrchestratorError( 'Cannot set values for --daemon-types, --services or --hosts when upgrade already in progress.') @@ -408,12 +413,8 @@ class CephadmUpgrade: if daemon_types is not None: dtypes = daemon_types if hosts is not None: - same_host_daemons = [ - d for d in daemons if d.hostname is not None and d.hostname in hosts] - other_host_daemons = [ - d for d in daemons if d.hostname is not None and d.hostname not in hosts] - daemons = (_get_earlier_daemons([_latest_type(dtypes)], other_host_daemons) - + _get_earlier_daemons(dtypes, same_host_daemons)) + daemons = (_get_earlier_daemons([_latest_type(dtypes)], _filter_by_hosts(daemons, hosts, False)) + + _get_earlier_daemons(dtypes, _filter_by_hosts(daemons, hosts, True))) else: daemons = _get_earlier_daemons(dtypes, daemons) err_msg_base += 'Daemons with types earlier in upgrade order than given types need upgrading.\n' @@ -431,12 +432,8 @@ class CephadmUpgrade: dtypes += orchestrator.service_to_daemon_types(stype) dtypes = list(set(dtypes)) if hosts is not None: - same_host_daemons = [ - d for d in daemons if d.hostname is not None and d.hostname in hosts] - other_host_daemons = [ - d for d in daemons if d.hostname is not None and d.hostname not in hosts] - daemons = (_get_earlier_daemons([_latest_type(dtypes)], other_host_daemons) - + _get_earlier_daemons(dtypes, same_host_daemons)) + daemons = (_get_earlier_daemons([_latest_type(dtypes)], _filter_by_hosts(daemons, hosts, False)) + + _get_earlier_daemons(dtypes, _filter_by_hosts(daemons, hosts, True))) else: daemons = _get_earlier_daemons(dtypes, daemons) err_msg_base += 'Daemons with types earlier in upgrade order than daemons from given services need upgrading.\n'