]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
qa/tasks/ceph: add task to rotate entity keys
authorPatrick Donnelly <pdonnell@ibm.com>
Thu, 29 May 2025 16:11:49 +0000 (12:11 -0400)
committerPatrick Donnelly <pdonnell@ibm.com>
Mon, 29 Dec 2025 22:31:58 +0000 (17:31 -0500)
Signed-off-by: Patrick Donnelly <pdonnell@ibm.com>
qa/tasks/ceph.py

index 6899b11a252b987a0f54d99a1c1ea183acb04543..9e735dc4ef0f3c9bdf74ac5d82c2e48ec41f8c2f 100644 (file)
@@ -1622,6 +1622,98 @@ def suppress_mon_health_to_clog(ctx, config):
     else:
         yield
 
+def _wait_for_up_and_clean(ctx, manager):
+    manager.wait_for_all_osds_up(timeout=300)
+
+    try:
+        manager.flush_all_pg_stats()
+    except (run.CommandFailedError, Exception) as e:
+        log.info('ignoring flush pg stats error, probably testing upgrade: %s', e)
+    manager.wait_for_clean()
+
+@contextlib.contextmanager
+def key_rotate(ctx, config):
+    """
+   rotate keys on ceph daemons
+
+   For example::
+      tasks:
+      - ceph.key_rotate: [all]
+
+   For example::
+      tasks:
+      - ceph.key_rotate:
+          daemons: [mon.*, mds.*, osd.0]
+          key_type: recommended
+
+    :param ctx: Context
+    :param config: Configuration
+    """
+    if config is None:
+        config = {}
+    elif isinstance(config, list):
+        config = {'daemons': config}
+
+    testdir = teuthology.get_testdir(ctx)
+
+    key_type = config.setdefault('key_type', 'recommended')
+    coverage_dir = f'{testdir}/archive/coverage'
+
+    cluster_name = config.setdefault('cluster', 'ceph')
+    manager = ctx.managers[cluster_name]
+
+    authtool = [
+        'sudo',
+        'adjust-ulimits',
+        'ceph-coverage',
+        coverage_dir,
+        'ceph-authtool',
+    ]
+
+    daemons = ctx.daemons.resolve_role_list(config.get('daemons', None), CEPH_ROLE_TYPES, True)
+    clusters = set()
+
+    new_mon_key = None
+    for role in daemons:
+        cluster, type_, id_ = teuthology.split_role(role)
+        daemon = ctx.daemons.get_daemon(type_, id_, cluster)
+        daemon.stop()
+        if type_ == 'osd':
+            manager.mark_down_osd(id_)
+
+        if type_ == 'mon':
+            if new_mon_key is None:
+                # mons are special and have a shared auth key, use "mon."
+                p = manager.ceph(f"auth rotate --key-type={key_type} mon.")
+                new_key = p.stdout.getvalue()
+                new_mon_key = new_key
+            else:
+                new_key = new_mon_key
+        else:
+            p = manager.ceph(f"auth rotate --key-type={key_type} {type_}.{id_}")
+            new_key = p.stdout.getvalue()
+
+        importme = '/tmp/importme'
+        log.info("generated new key %s", new_key)
+        daemon.remote.write_file(importme, BytesIO(new_key.encode()))
+
+        daemon_dir = DATA_PATH.format(type_=type_, cluster=cluster_name, id_=id_)
+        authimport = [
+          *authtool,
+          '--import-keyring',
+          importme,
+          os.path.join(daemon_dir, 'keyring')
+        ]
+        daemon.remote.run(args=['sudo', 'cat', importme])
+        daemon.remote.run(args=['sudo', 'cat', os.path.join(daemon_dir, 'keyring')])
+        daemon.remote.run(args=authimport)
+        daemon.remote.run(args=['sudo', 'cat', os.path.join(daemon_dir, 'keyring')])
+
+        daemon.restart()
+
+    yield
+
+
 @contextlib.contextmanager
 def restart(ctx, config):
     """