]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
erasure-code: add crush rule profile to suites
authorNitzan Mordechai <nmordech@redhat.com>
Tue, 8 Aug 2023 07:44:34 +0000 (07:44 +0000)
committernmordech@redhat.com <nmordech@redhat.com>
Wed, 28 Feb 2024 07:21:27 +0000 (07:21 +0000)
Adding new yaml entry to handle create of crush profile before
creating new pool, will be skipped if no crush profile name
was set.

Signed-off-by: Nitzan Mordechai <nmordech@redhat.com>
qa/tasks/ceph_manager.py
qa/tasks/rados.py
qa/tasks/util/rados.py

index 95e5dac51aba96f0477a4bb76e1f377aa57d43fc..4690896b768205c649a286ee9eee425ba42a49b7 100644 (file)
@@ -20,7 +20,7 @@ from io import BytesIO, StringIO
 from subprocess import DEVNULL
 from teuthology import misc as teuthology
 from tasks.scrub import Scrubber
-from tasks.util.rados import cmd_erasure_code_profile
+from tasks.util.rados import cmd_erasure_code_profile, cmd_ec_crush_profile
 from tasks.util import get_remote
 
 from teuthology.contextutil import safe_while
@@ -2114,8 +2114,18 @@ class CephManager:
             args = cmd_erasure_code_profile(profile_name, profile)
             self.raw_cluster_cmd(*args)
 
+    def create_erasure_code_crush_rule(self, rule_name, profile):
+        """
+        Create an erasure code crush rule that can be used as a parameter
+        when creating an erasure coded pool.
+        """
+        with self.lock:
+            args = cmd_ec_crush_profile(rule_name, profile)
+            self.raw_cluster_cmd(*args)
+
     def create_pool_with_unique_name(self, pg_num=16,
                                      erasure_code_profile_name=None,
+                                     erasure_code_crush_rule_name=None,
                                      min_size=None,
                                      erasure_code_use_overwrites=False):
         """
@@ -2129,6 +2139,7 @@ class CephManager:
                 name,
                 pg_num,
                 erasure_code_profile_name=erasure_code_profile_name,
+                erasure_code_crush_rule_name=erasure_code_crush_rule_name,
                 min_size=min_size,
                 erasure_code_use_overwrites=erasure_code_use_overwrites)
         return name
@@ -2141,6 +2152,7 @@ class CephManager:
 
     def create_pool(self, pool_name, pg_num=16,
                     erasure_code_profile_name=None,
+                    erasure_code_crush_rule_name=None,
                     min_size=None,
                     erasure_code_use_overwrites=False):
         """
@@ -2149,6 +2161,8 @@ class CephManager:
         :param pg_num: initial number of pgs.
         :param erasure_code_profile_name: if set and !None create an
                                           erasure coded pool using the profile
+        :param erasure_code_crush_rule_name: if set and !None create an
+                                             erasure coded pool using the crush rule
         :param erasure_code_use_overwrites: if true, allow overwrites
         """
         with self.lock:
@@ -2157,9 +2171,14 @@ class CephManager:
             assert pool_name not in self.pools
             self.log("creating pool_name %s" % (pool_name,))
             if erasure_code_profile_name:
-                self.raw_cluster_cmd('osd', 'pool', 'create',
-                                     pool_name, str(pg_num), str(pg_num),
-                                     'erasure', erasure_code_profile_name)
+                cmd_args = ['osd', 'pool', 'create', 
+                            pool_name, str(pg_num), 
+                            str(pg_num), 'erasure', 
+                            erasure_code_profile_name]
+
+                if erasure_code_crush_rule_name:
+                    cmd_args.extend([erasure_code_crush_rule_name])
+                self.raw_cluster_cmd(*cmd_args)
             else:
                 self.raw_cluster_cmd('osd', 'pool', 'create',
                                      pool_name, str(pg_num))
index 7e786fb68e7ef23b0c21da20ab32af10713945ac..44dfd8d4215cde383e6dc3b20111dfe9548935c1 100644 (file)
@@ -237,8 +237,16 @@ def task(ctx, config):
             profile = config.get('erasure_code_profile', {})
             profile_name = profile.get('name', 'teuthologyprofile')
             manager.create_erasure_code_profile(profile_name, profile)
+            crush_prof = config.get('erasure_code_crush', {})
+            crush_name = None
+            if crush_prof:
+                crush_name = crush_prof.get('name', 'teuthologycrush')
+                manager.create_erasure_code_crush_rule(crush_name, crush_prof)
+
         else:
             profile_name = None
+            crush_name = None
+
         for i in range(int(config.get('runs', '1'))):
             log.info("starting run %s out of %s", str(i), config.get('runs', '1'))
             tests = {}
@@ -256,6 +264,7 @@ def task(ctx, config):
                 else:
                     pool = manager.create_pool_with_unique_name(
                         erasure_code_profile_name=profile_name,
+                        erasure_code_crush_rule_name=crush_name,
                         erasure_code_use_overwrites=
                           config.get('erasure_code_use_overwrites', False)
                     )
index a0c54ce4eadc711ce3405e6d511725ad1980c2c1..f3936216477fe362b1df91160d4668a43661187c 100644 (file)
@@ -1,6 +1,7 @@
 import logging
 
 from teuthology import misc as teuthology
+from teuthology.orchestra.run import Raw
 
 log = logging.getLogger(__name__)
 
@@ -85,3 +86,35 @@ def cmd_erasure_code_profile(profile_name, profile):
         'osd', 'erasure-code-profile', 'set',
         profile_name
         ] + [ str(key) + '=' + str(value) for key, value in profile.items() ]
+
+def cmd_ec_crush_profile(crush_name, profile):
+    """
+    Return the shell command to run to create the erasure code crush rule
+    described by the profile parameter.
+    
+    :param crush_name: a string matching [A-Za-z0-9-_.]+
+    :param profile: a map whose semantic depends on the crush rule syntax
+    :returns: a shell command as an array suitable for Remote.run
+
+    If profile is {}, return an empty list.
+    """
+
+    if profile == {}:
+        return []
+
+    id_value = profile.get('id', 1)
+    ec_type = profile.get('type', 'erasure')
+    min_size = profile.get('min_size', 1)
+    max_size = profile.get('max_size', 10)
+    steps = profile.get('steps', [])
+
+    crush_content = f"rule {crush_name}-{id_value} {{"
+    crush_content += f"    id {id_value}"
+    crush_content += f"    type {ec_type}"
+    crush_content += f"    min_size {min_size}"
+    crush_content += f"    max_size {max_size}"
+    for step in steps:
+        crush_content += f"    step {step}"
+    crush_content += "}"
+
+    return ['osd', 'crush', 'rule', 'create-erasure', crush_name, '-i', '-', Raw("<<<"), crush_content]