]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/balancer: auto balance a list of pools
authorxie xingguo <xie.xingguo@zte.com.cn>
Mon, 17 Dec 2018 08:53:44 +0000 (16:53 +0800)
committerxie xingguo <xie.xingguo@zte.com.cn>
Mon, 14 Jan 2019 10:23:41 +0000 (18:23 +0800)
Add support which limits the auto balancer to a comma-separated list of pools.

Signed-off-by: xie xingguo <xie.xingguo@zte.com.cn>
src/pybind/mgr/balancer/module.py

index 076a064b4a952862fad5f5332b3b2cd942681192..cf9ec56d51510ea2d288c2e47a9d661888544ea3 100644 (file)
@@ -286,6 +286,13 @@ class Module(MgrModule):
             'long_desc': 'If the ratio between the fullest and least-full OSD is below this value then we stop trying to optimize placement.',
             'runtime': True,
         },
+        {
+            'name': 'pool_ids',
+            'type': 'str',
+            'default': '',
+            'desc': 'pools which the automatic balancing will be limited to',
+            'runtime': True,
+        },
     ]
 
     COMMANDS = [
@@ -309,6 +316,23 @@ class Module(MgrModule):
             "desc": "Disable automatic balancing",
             "perm": "rw",
         },
+        {
+            "cmd": "balancer pool ls",
+            "desc": "List automatic balancing pools. "
+                    "Note that empty list means all existing pools will be automatic balancing targets, "
+                    "which is the default behaviour of balancer.",
+            "perm": "r",
+        },
+        {
+            "cmd": "balancer pool add name=pools,type=CephString,n=N",
+            "desc": "Enable automatic balancing for specific pools",
+            "perm": "rw",
+        },
+        {
+            "cmd": "balancer pool rm name=pools,type=CephString,n=N",
+            "desc": "Disable automatic balancing for specific pools",
+            "perm": "rw",
+        },
         {
             "cmd": "balancer eval name=option,type=CephString,req=false",
             "desc": "Evaluate data distribution for the current cluster or specific pool or specific plan",
@@ -388,6 +412,53 @@ class Module(MgrModule):
                 self.active = False
             self.event.set()
             return (0, '', '')
+        elif command['prefix'] == 'balancer pool ls':
+            pool_ids = self.get_module_option('pool_ids')
+            if pool_ids is '':
+                return (0, '', '')
+            pool_ids = pool_ids.split(',')
+            pool_ids = [int(p) for p in pool_ids]
+            pool_name_by_id = dict((p['pool'], p['pool_name']) for p in self.get_osdmap().dump().get('pools', []))
+            should_prune = False
+            final_ids = []
+            final_names = []
+            for p in pool_ids:
+                if p in pool_name_by_id:
+                    final_ids.append(p)
+                    final_names.append(pool_name_by_id[p])
+                else:
+                    should_prune = True
+            if should_prune: # some pools were gone, prune
+                self.set_module_option('pool_ids', ','.join(final_ids))
+            return (0, json.dumps(final_names, indent=4), '')
+        elif command['prefix'] == 'balancer pool add':
+            raw_names = command['pools']
+            pool_id_by_name = dict((p['pool_name'], p['pool']) for p in self.get_osdmap().dump().get('pools', []))
+            invalid_names = [p for p in raw_names if p not in pool_id_by_name]
+            if invalid_names:
+                return (-errno.EINVAL, '', 'pool(s) %s not found' % invalid_names)
+            to_add = [str(pool_id_by_name[p]) for p in raw_names if p in pool_id_by_name]
+            existing = self.get_module_option('pool_ids')
+            final = to_add
+            if existing is not '':
+                existing = existing.split(',')
+                final = set(to_add) | set(existing)
+            self.set_module_option('pool_ids', ','.join(final))
+            return (0, '', '')
+        elif command['prefix'] == 'balancer pool rm':
+            raw_names = command['pools']
+            existing = self.get_module_option('pool_ids')
+            if existing is '': # for idempotence
+                return (0, '', '')
+            existing = existing.split(',')
+            osdmap = self.get_osdmap()
+            pool_ids = [str(p['pool']) for p in osdmap.dump().get('pools', [])]
+            pool_id_by_name = dict((p['pool_name'], p['pool']) for p in osdmap.dump().get('pools', []))
+            final = [p for p in existing if p in pool_ids]
+            to_delete = [str(pool_id_by_name[p]) for p in raw_names if p in pool_id_by_name]
+            final = set(final) - set(to_delete)
+            self.set_module_option('pool_ids', ','.join(final))
+            return (0, '', '')
         elif command['prefix'] == 'balancer eval' or command['prefix'] == 'balancer eval-verbose':
             verbose = command['prefix'] == 'balancer eval-verbose'
             pools = []
@@ -483,7 +554,19 @@ class Module(MgrModule):
             if self.active and self.time_in_interval(timeofday, begin_time, end_time):
                 self.log.debug('Running')
                 name = 'auto_%s' % time.strftime(TIME_FORMAT, time.gmtime())
-                plan = self.plan_create(name, self.get_osdmap(), [])
+                osdmap = self.get_osdmap()
+                allow = self.get_module_option('pool_ids')
+                final = []
+                if allow is not '':
+                    allow = allow.split(',')
+                    valid = [str(p['pool']) for p in osdmap.dump().get('pools', [])]
+                    final = set(allow) & set(valid)
+                    if set(allow) - set(valid): # some pools were gone, prune
+                        self.set_module_option('pool_ids', ','.join(final))
+                    pool_name_by_id = dict((p['pool'], p['pool_name']) for p in osdmap.dump().get('pools', []))
+                    final = [int(p) for p in final]
+                    final = [pool_name_by_id[p] for p in final if p in pool_name_by_id]
+                plan = self.plan_create(name, osdmap, final)
                 r, detail = self.optimize(plan)
                 if r == 0:
                     self.execute(plan)