]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/cephadm: block draining last _admin host 45229/head
authorAdam King <adking@redhat.com>
Fri, 25 Feb 2022 22:55:06 +0000 (17:55 -0500)
committerAdam King <adking@redhat.com>
Wed, 2 Mar 2022 19:43:35 +0000 (14:43 -0500)
Fixes: https://tracker.ceph.com/issues/54413
Signed-off-by: Adam King <adking@redhat.com>
(cherry picked from commit a0d21c7108e8f95b541bdb7653d2595f68e42520)

src/pybind/mgr/cephadm/module.py
src/pybind/mgr/orchestrator/_interface.py
src/pybind/mgr/orchestrator/module.py

index 13b5040ed98bc873894117e0e51c74fc82de96a0..13784fdebfd77fdae3e94b96465440e8d8db5331 100644 (file)
@@ -2832,12 +2832,26 @@ Then run the following:
         return self.to_remove_osds.all_osds()
 
     @handle_orch_error
-    def drain_host(self, hostname):
-        # type: (str) -> str
+    def drain_host(self, hostname, force=False):
+        # type: (str, bool) -> str
         """
         Drain all daemons from a host.
         :param host: host name
         """
+
+        # if we drain the last admin host we could end up removing the only instance
+        # of the config and keyring and cause issues
+        if not force:
+            p = PlacementSpec(label='_admin')
+            admin_hosts = p.filter_matching_hostspecs(self.inventory.all_specs())
+            if len(admin_hosts) == 1 and admin_hosts[0] == hostname:
+                raise OrchestratorValidationError(f"Host {hostname} is the last host with the '_admin'"
+                                                  " label.\nDraining this host could cause the removal"
+                                                  " of the last cluster config/keyring managed by cephadm.\n"
+                                                  "It is recommended to add the _admin label to another host"
+                                                  " before completing this operation.\nIf you're certain this is"
+                                                  " what you want rerun this command with --force.")
+
         self.add_host_label(hostname, '_no_schedule')
 
         daemons: List[orchestrator.DaemonDescription] = self.cache.get_daemons_by_host(hostname)
index a1b1893db0cdfc97ed703dbb2d9583907ab812af..eeecb4e2bec172f3289d3f57db2f3f8b458bd5d4 100644 (file)
@@ -355,7 +355,7 @@ class Orchestrator(object):
         """
         raise NotImplementedError()
 
-    def drain_host(self, hostname: str) -> OrchResult[str]:
+    def drain_host(self, hostname: str, force: bool = False) -> OrchResult[str]:
         """
         drain all daemons from a host
 
index 10381db9c14a7bcf53b09129dd82cb83021b2b15..e23233cb7a7c8628e768f5348df2372f77539769 100644 (file)
@@ -358,9 +358,9 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
         return HandleCommandResult(stdout=completion.result_str())
 
     @_cli_write_command('orch host drain')
-    def _drain_host(self, hostname: str) -> HandleCommandResult:
+    def _drain_host(self, hostname: str, force: bool = False) -> HandleCommandResult:
         """drain all daemons from a host"""
-        completion = self.drain_host(hostname)
+        completion = self.drain_host(hostname, force)
         raise_if_exception(completion)
         return HandleCommandResult(stdout=completion.result_str())