]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/cephadm: add daemon 'rotate-key' action
authorSage Weil <sage@newdream.net>
Tue, 26 Oct 2021 17:30:36 +0000 (13:30 -0400)
committerRadoslaw Zarzynski <rzarzyns@redhat.com>
Mon, 12 Sep 2022 17:03:32 +0000 (17:03 +0000)
Caveats:
- only works with osd, mds, mgr so far
- sometimes we have to restart the daemon

Signed-off-by: Sage Weil <sage@newdream.net>
src/pybind/mgr/cephadm/inventory.py
src/pybind/mgr/cephadm/module.py
src/pybind/mgr/orchestrator/module.py

index 04385a4fa81cc8e31b420133fcc487bb7b27ecbe..149ee1238409b27ac98ed2bbf3e772976c54c883 100644 (file)
@@ -1236,6 +1236,7 @@ class HostCache():
             'reconfig': 3,
             'redeploy': 4,
             'stop': 5,
+            'rotate-key': 6,
         }
         existing_action = self.scheduled_daemon_actions.get(host, {}).get(daemon_name, None)
         if existing_action and priorities[existing_action] > priorities[action]:
index e3d90f13aebd24b5efaea19e43c7a4dc406ba2c5..2c0e7068bd5305e538e9645b39630249ffc27228 100644 (file)
@@ -1989,6 +1989,52 @@ Then run the following:
             for dd in dds
         ]
 
+    def _rotate_daemon_key(self, daemon_spec: CephadmDaemonDeploySpec) -> str:
+        self.log.info(f'Rotating authentication key for {daemon_spec.name()}')
+        rc, out, err = self.mon_command({
+            'prefix': 'auth get-or-create-pending',
+            'entity': daemon_spec.name(),
+            'format': 'json',
+        })
+        j = json.loads(out)
+        pending_key = j[0]['pending_key']
+
+        # deploy a new keyring file
+        if daemon_spec.daemon_type != 'osd':
+            daemon_spec = self.cephadm_services[daemon_type_to_service(
+                daemon_spec.daemon_type)].prepare_create(daemon_spec)
+        CephadmServe(self)._create_daemon(daemon_spec, reconfig=True)
+
+        # try to be clever, or fall back to restarting the daemon
+        rc = -1
+        if daemon_spec.daemon_type == 'osd':
+            rc, out, err = self.tool_exec(
+                args=['ceph', 'tell', daemon_spec.name(), 'rotate-stored-key', '-i', '-'],
+                stdin=pending_key.encode()
+            )
+            if not rc:
+                rc, out, err = self.tool_exec(
+                    args=['ceph', 'tell', daemon_spec.name(), 'rotate-key', '-i', '-'],
+                    stdin=pending_key.encode()
+                )
+        elif daemon_spec.daemon_type == 'mds':
+            rc, out, err = self.tool_exec(
+                args=['ceph', 'tell', daemon_spec.name(), 'rotate-key', '-i', '-'],
+                stdin=pending_key.encode()
+            )
+        elif (
+                daemon_spec.daemon_type == 'mgr'
+                and daemon_spec.daemon_id == self.get_mgr_id()
+        ):
+            rc, out, err = self.tool_exec(
+                args=['ceph', 'tell', daemon_spec.name(), 'rotate-key', '-i', '-'],
+                stdin=pending_key.encode()
+            )
+        if rc:
+            self._daemon_action(daemon_spec, 'restart')
+
+        return f'Rotated key for {daemon_spec.name()}'
+
     def _daemon_action(self,
                        daemon_spec: CephadmDaemonDeploySpec,
                        action: str,
@@ -2001,6 +2047,9 @@ Then run the following:
             self.mgr_service.fail_over()
             return ''  # unreachable
 
+        if action == 'rotate-key':
+            return self._rotate_daemon_key(daemon_spec)
+
         if action == 'redeploy' or action == 'reconfig':
             if daemon_spec.daemon_type != 'osd':
                 daemon_spec = self.cephadm_services[daemon_type_to_service(
@@ -2057,6 +2106,12 @@ Then run the following:
             raise OrchestratorError(
                 f'Unable to schedule redeploy for {daemon_name}: No standby MGRs')
 
+        if action == 'rotate-key':
+            if d.daemon_type not in ['mgr', 'osd', 'mds']:
+                raise OrchestratorError(
+                    f'key rotation not supported for {d.daemon_type}'
+                )
+
         self._daemon_action_set_image(action, image, d.daemon_type, d.daemon_id)
 
         self.log.info(f'Schedule {action} daemon {daemon_name}')
index fe975ff0c3dc805a2a6ec9e7ecf92aaf5338424f..1fd9eebd9b949da173bd944d9350787b3504d5e0 100644 (file)
@@ -74,6 +74,7 @@ class ServiceAction(enum.Enum):
     restart = 'restart'
     redeploy = 'redeploy'
     reconfig = 'reconfig'
+    rotate_key = 'rotate-key'
 
 
 class DaemonAction(enum.Enum):
@@ -81,6 +82,7 @@ class DaemonAction(enum.Enum):
     stop = 'stop'
     restart = 'restart'
     reconfig = 'reconfig'
+    rotate_key = 'rotate-key'
 
 
 def to_format(what: Any, format: Format, many: bool, cls: Any) -> Any:
@@ -1008,7 +1010,7 @@ Usage:
 
     @_cli_write_command('orch daemon')
     def _daemon_action(self, action: DaemonAction, name: str) -> HandleCommandResult:
-        """Start, stop, restart, (redeploy,) or reconfig a specific daemon"""
+        """Start, stop, restart, redeploy, reconfig, or rotate-key for a specific daemon"""
         if '.' not in name:
             raise OrchestratorError('%s is not a valid daemon name' % name)
         completion = self.daemon_action(action.value, name)
@@ -1019,7 +1021,7 @@ Usage:
     def _daemon_action_redeploy(self,
                                 name: str,
                                 image: Optional[str] = None) -> HandleCommandResult:
-        """Redeploy a daemon (with a specifc image)"""
+        """Redeploy a daemon (with a specific image)"""
         if '.' not in name:
             raise OrchestratorError('%s is not a valid daemon name' % name)
         completion = self.daemon_action("redeploy", name, image=image)