From d8d808cf30eb5406e8cf6545d6c9900bc1e2be58 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 6 Mar 2021 10:10:42 -0500 Subject: [PATCH] mgr/cephadm/schedule: respect count-per-host In the no-count cases, our job is simple: we have a set of hosts specified via some other means (label, filter, explicit list) and simply need to do N instances for each of those hosts. Signed-off-by: Sage Weil --- src/pybind/mgr/cephadm/schedule.py | 23 +++++++++------ .../mgr/cephadm/tests/test_scheduling.py | 28 +++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/pybind/mgr/cephadm/schedule.py b/src/pybind/mgr/cephadm/schedule.py index b6cb3f4841bc..794297e7c1af 100644 --- a/src/pybind/mgr/cephadm/schedule.py +++ b/src/pybind/mgr/cephadm/schedule.py @@ -116,21 +116,28 @@ class HostAssignment(object): count = self.spec.placement.count - # get candidates based on [hosts, label, host_pattern] - candidates = self.get_candidates() + # get candidate hosts based on [hosts, label, host_pattern] + candidates = self.get_candidates() # type: List[HostPlacementSpec] # If we don't have the list of candidates is definitive. if count is None: logger.debug('Provided hosts: %s' % candidates) + + if self.spec.placement.count_per_host: + per_host = self.spec.placement.count_per_host + else: + per_host = 1 + # do not deploy ha-rgw on hosts that don't support virtual ips if self.spec.service_type == 'ha-rgw' and self.filter_new_host: old = candidates candidates = [h for h in candidates if self.filter_new_host(h.hostname)] for h in list(set(old) - set(candidates)): logger.info( - f"Filtered out host {h.hostname} for ha-rgw. Could not verify host allowed virtual ips") - logger.info('filtered %s down to %s' % (old, candidates)) - return candidates + f"Filtered out host {h.hostname} for ha-rgw: could not verify host allowed virtual ips") + logger.debug('Filtered %s down to %s' % (old, candidates)) + + return candidates * per_host # prefer hosts that already have services. # this avoids re-assigning to _new_ hosts @@ -141,7 +148,7 @@ class HostAssignment(object): # The amount of hosts that need to be selected in order to fulfill count. need = count - len(hosts_with_daemons) - # hostspecs that are do not have daemons on them but are still candidates. + # hostspecs that do not have daemons on them but are still candidates. others = difference_hostspecs(candidates, hosts_with_daemons) # we don't need any additional hosts @@ -215,12 +222,12 @@ class HostAssignment(object): def get_candidates(self) -> List[HostPlacementSpec]: if self.spec.placement.hosts: return self.spec.placement.hosts - elif self.spec.placement.label: + if self.spec.placement.label: return [ HostPlacementSpec(x.hostname, '', '') for x in self.hosts_by_label(self.spec.placement.label) ] - elif self.spec.placement.host_pattern: + if self.spec.placement.host_pattern: return [ HostPlacementSpec(x, '', '') for x in self.spec.placement.filter_matching_hostspecs(self.hosts) diff --git a/src/pybind/mgr/cephadm/tests/test_scheduling.py b/src/pybind/mgr/cephadm/tests/test_scheduling.py index 5066c7dab1ac..78f38b07b82c 100644 --- a/src/pybind/mgr/cephadm/tests/test_scheduling.py +++ b/src/pybind/mgr/cephadm/tests/test_scheduling.py @@ -349,6 +349,17 @@ class NodeAssignmentTest(NamedTuple): ], ['host1', 'host2', 'host3'] ), + # all_hosts + count_per_host + NodeAssignmentTest( + 'mgr', + PlacementSpec(host_pattern='*', count_per_host=2), + 'host1 host2 host3'.split(), + [ + DaemonDescription('mgr', 'a', 'host1'), + DaemonDescription('mgr', 'b', 'host2'), + ], + ['host1', 'host2', 'host3', 'host1', 'host2', 'host3'] + ), # count that is bigger than the amount of hosts. Truncate to len(hosts) # RGWs should not be co-located to each other. NodeAssignmentTest( @@ -418,6 +429,15 @@ class NodeAssignmentTest(NamedTuple): [], ['host1', 'host2', 'host3'] ), + # label only + count_per_hst + NodeAssignmentTest( + 'mgr', + PlacementSpec(label='foo', count_per_host=3), + 'host1 host2 host3'.split(), + [], + ['host1', 'host2', 'host3', 'host1', 'host2', 'host3', + 'host1', 'host2', 'host3'] + ), # host_pattern NodeAssignmentTest( 'mgr', @@ -426,6 +446,14 @@ class NodeAssignmentTest(NamedTuple): [], ['mgrhost1', 'mgrhost2'] ), + # host_pattern + count_per_host + NodeAssignmentTest( + 'mgr', + PlacementSpec(host_pattern='mgr*', count_per_host=3), + 'mgrhost1 mgrhost2 datahost'.split(), + [], + ['mgrhost1', 'mgrhost2', 'mgrhost1', 'mgrhost2', 'mgrhost1', 'mgrhost2'] + ), ]) def test_node_assignment(service_type, placement, hosts, daemons, expected): service_id = None -- 2.47.3